├── .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
├── sponsors
├── auth0-dark.png
├── auth0.png
├── descope-dark.svg
├── descope.svg
├── fusionauth.png
├── fusionauth.svg
├── loginradius.png
├── snyk.png
├── stytch-dark.png
├── stytch.png
└── workos.png
└── 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
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: jaredhanson
2 | patreon: jaredhanson
3 | ko_fi: jaredhanson
4 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ** READ THIS FIRST! **
2 |
3 | #### Are you looking for help?
4 |
5 | Reminder: The issue tracker is not a support forum.
6 |
7 | Issues should only be filed in this project once they are able to be reproduced
8 | and confirmed as a flaw in the software or incorrect information in associated
9 | documention.
10 |
11 | If you are encountering problems integrating this module into your application,
12 | please post a question on the [discussion forum](https://github.com/passport/discuss)
13 | rather than filing an issue.
14 |
15 | #### Is this a security issue?
16 |
17 | Do not open issues that might have security implications. Potential security
18 | vulnerabilities should be reported privately to jaredhanson@gmail.com. Once any
19 | vulerabilities have been repaired, the details will be disclosed publicly in a
20 | responsible manner. This also allows time for coordinating with affected parties
21 | in order to mitigate negative consequences.
22 |
23 |
24 | If neither of the above two scenarios apply to your situation, you should open
25 | an issue. Delete this paragraph and the text above, and fill in the information
26 | requested below.
27 |
28 |
29 |
30 |
31 |
32 |
33 | ### Expected behavior
34 |
35 |
36 |
37 | ### Actual behavior
38 |
39 |
40 |
41 | ### Steps to reproduce
42 |
43 |
44 |
45 | ```js
46 | // Format code using Markdown code blocks
47 | ```
48 |
49 | ### Environment
50 |
51 | * Operating System:
52 | * Node version:
53 | * passport version:
54 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ** READ THIS FIRST! **
2 |
3 | #### Are you implementing a new feature?
4 |
5 | Requests for new features should first be discussed on the [developer forum](https://github.com/passport/develop).
6 | This allows the community to gather feedback and assess whether or not there is
7 | an existing way to achieve the desired functionality.
8 |
9 | If it is determined that a new feature needs to be implemented, include a link
10 | to the relevant discussion along with the pull request.
11 |
12 | #### Is this a security patch?
13 |
14 | Do not open pull requests that might have security implications. Potential
15 | security vulnerabilities should be reported privately to jaredhanson@gmail.com.
16 | Once any vulerabilities have been repaired, the details will be disclosed
17 | publicly in a responsible manner. This also allows time for coordinating with
18 | affected parties in order to mitigate negative consequences.
19 |
20 |
21 | If neither of the above two scenarios apply to your situation, you should open
22 | a pull request. Delete this paragraph and the text above, and fill in the
23 | information requested below.
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | ### Checklist
33 |
34 |
35 |
36 |
37 | - [ ] I have read the [CONTRIBUTING](https://github.com/jaredhanson/passport/blob/master/CONTRIBUTING.md) guidelines.
38 | - [ ] I have added test cases which verify the correct operation of this feature or patch.
39 | - [ ] I have added documentation pertaining to this feature or patch.
40 | - [ ] The automated test suite (`$ make test`) executes successfully.
41 | - [ ] The automated code linting (`$ make lint`) executes successfully.
42 |
--------------------------------------------------------------------------------
/.github/workflows/node.yml:
--------------------------------------------------------------------------------
1 | # 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
2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
3 |
4 | name: Node.js CI
5 |
6 | on:
7 | push:
8 | branches: [ master ]
9 | pull_request:
10 | branches: [ master ]
11 |
12 | jobs:
13 | build:
14 |
15 | runs-on: ubuntu-latest
16 |
17 | strategy:
18 | matrix:
19 | node-version:
20 | - '17'
21 | - '16'
22 | - '14'
23 | - '12'
24 | - '10'
25 | - '8'
26 | - '6'
27 | - '4'
28 | # - '3' # io.js
29 | # - '2' # io.js
30 | # - '1' # io.js
31 | - '0.12'
32 | - '0.10'
33 | # - '0.8'
34 |
35 | steps:
36 | - uses: actions/checkout@v2
37 | - name: Use Node.js ${{ matrix.node-version }}
38 | uses: actions/setup-node@v2
39 | with:
40 | node-version: ${{ matrix.node-version }}
41 | - run: npm install
42 | - run: npm test
43 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | docs/
2 | reports/
3 |
4 | # Mac OS X
5 | .DS_Store
6 |
7 | # Node.js
8 | node_modules
9 | npm-debug.log
10 |
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "node": true,
3 | "bitwise": true,
4 | "camelcase": true,
5 | "curly": true,
6 | "forin": true,
7 | "immed": true,
8 | "latedef": true,
9 | "newcap": true,
10 | "noarg": true,
11 | "noempty": true,
12 | "nonew": true,
13 | "quotmark": "single",
14 | "undef": true,
15 | "unused": true,
16 | "trailing": true,
17 | "laxcomma": true
18 | }
19 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | CONTRIBUTING.md
2 | Makefile
3 | SPONSORS.md
4 | docs/
5 | examples/
6 | reports/
7 | test/
8 |
9 | .github/
10 | .jshintrc
11 | .travis.yml
12 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: "node_js"
2 | node_js:
3 | - "13"
4 | - "12"
5 | - "11"
6 | - "10"
7 | - "9"
8 | - "8"
9 | - "7"
10 | - "6"
11 | - "5"
12 | - "4"
13 | - "3" # io.js
14 | - "2" # io.js
15 | - "1" # io.js
16 | - "0.12"
17 | - "0.10"
18 | # - "0.8"
19 |
20 |
21 | before_install:
22 | - "npm install make-node@0.3.x -g"
23 | - "preinstall-compat"
24 |
25 | script:
26 | - "make test-cov"
27 |
28 | after_success:
29 | - "make report-cov"
30 |
31 | sudo: false
32 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 | All notable changes to this project will be documented in this file.
3 |
4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6 |
7 | ## [Unreleased]
8 |
9 | ## [0.7.0] - 2023-11-27
10 | ### Changed
11 | - Set `req.authInfo` by default when using the `assignProperty` option to
12 | `authenticate()` middleware. This makes the behavior the same as when not using
13 | the option, and can be disabled by setting `authInfo` option to `false`.
14 |
15 | ## [0.6.0] - 2022-05-20
16 | ### Added
17 | - `authenticate()`, `req#login`, and `req#logout` accept a
18 | `keepSessionInfo: true` option to keep session information after regenerating
19 | the session.
20 |
21 | ### Changed
22 |
23 | - `req#login()` and `req#logout()` regenerate the the session and clear session
24 | information by default.
25 | - `req#logout()` is now an asynchronous function and requires a callback
26 | function as the last argument.
27 |
28 | ### Security
29 |
30 | - Improved robustness against session fixation attacks in cases where there is
31 | physical access to the same system or the application is susceptible to
32 | cross-site scripting (XSS).
33 |
34 | ## [0.5.3] - 2022-05-16
35 | ### Fixed
36 |
37 | - `initialize()` middleware extends request with `login()`, `logIn()`,
38 | `logout()`, `logOut()`, `isAuthenticated()`, and `isUnauthenticated()` functions
39 | again, reverting change from 0.5.1.
40 |
41 | ## [0.5.2] - 2021-12-16
42 | ### Fixed
43 | - Introduced a compatibility layer for strategies that depend directly on
44 | `passport@0.4.x` or earlier (such as `passport-azure-ad`), which were
45 | broken by the removal of private variables in `passport@0.5.1`.
46 |
47 | ## [0.5.1] - 2021-12-15
48 | ### Added
49 | - Informative error message in session strategy if session support is not
50 | available.
51 |
52 | ### Changed
53 |
54 | - `authenticate()` middleware, rather than `initialize()` middleware, extends
55 | request with `login()`, `logIn()`, `logout()`, `logOut()`, `isAuthenticated()`,
56 | and `isUnauthenticated()` functions.
57 |
58 | ## [0.5.0] - 2021-09-23
59 | ### Changed
60 |
61 | - `initialize()` middleware extends request with `login()`, `logIn()`,
62 | `logout()`, `logOut()`, `isAuthenticated()`, and `isUnauthenticated()`
63 | functions.
64 |
65 | ### Removed
66 |
67 | - `login()`, `logIn()`, `logout()`, `logOut()`, `isAuthenticated()`, and
68 | `isUnauthenticated()` functions no longer added to `http.IncomingMessage.prototype`.
69 |
70 | ### Fixed
71 |
72 | - `userProperty` option to `initialize()` middleware only affects the current
73 | request, rather than all requests processed via singleton Passport instance,
74 | eliminating a race condition in situations where `initialize()` middleware is
75 | used multiple times in an application with `userProperty` set to different
76 | values.
77 |
78 | [Unreleased]: https://github.com/jaredhanson/passport/compare/v0.6.0...HEAD
79 | [0.6.0]: https://github.com/jaredhanson/passport/compare/v0.5.3...v0.6.0
80 | [0.5.3]: https://github.com/jaredhanson/passport/compare/v0.5.2...v0.5.3
81 | [0.5.2]: https://github.com/jaredhanson/passport/compare/v0.5.1...v0.5.2
82 | [0.5.1]: https://github.com/jaredhanson/passport/compare/v0.5.0...v0.5.1
83 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | ## Contributing
2 |
3 | ### Tests
4 |
5 | The test suite is located in the `test/` directory. All new features are
6 | expected to have corresponding test cases with complete code coverage. Patches
7 | that increase test coverage are happily accepted.
8 |
9 | Ensure that the test suite passes by executing:
10 |
11 | ```bash
12 | $ make test
13 | ```
14 |
15 | Coverage reports can be generated and viewed by executing:
16 |
17 | ```bash
18 | $ make test-cov
19 | $ make view-cov
20 | ```
21 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2011-2021 Jared Hanson
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | include node_modules/make-node/main.mk
2 |
3 |
4 | SOURCES = lib/*.js lib/**/*.js
5 | TESTS = test/*.test.js test/**/*.test.js
6 |
7 | LCOVFILE = ./reports/coverage/lcov.info
8 |
9 | MOCHAFLAGS = --require ./test/bootstrap/node
10 |
11 |
12 | view-docs:
13 | open ./docs/index.html
14 |
15 | view-cov:
16 | open ./reports/coverage/lcov-report/index.html
17 |
18 | clean: clean-docs clean-cov
19 | -rm -r $(REPORTSDIR)
20 |
21 | clobber: clean
22 | -rm -r node_modules
23 |
24 | html:
25 | jsdoc -c etc/jsdoc.json -d ./doc $(SOURCES)
26 |
27 |
28 | .PHONY: clean clobber
29 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](http://passportjs.org)
2 |
3 | # Passport
4 |
5 | Passport is [Express](http://expressjs.com/)-compatible authentication
6 | middleware for [Node.js](http://nodejs.org/).
7 |
8 | Passport's sole purpose is to authenticate requests, which it does through an
9 | extensible set of plugins known as _strategies_. Passport does not mount
10 | routes or assume any particular database schema, which maximizes flexibility and
11 | allows application-level decisions to be made by the developer. The API is
12 | simple: you provide Passport a request to authenticate, and Passport provides
13 | hooks for controlling what occurs when authentication succeeds or fails.
14 |
15 | ---
16 |
17 |
18 |
Sponsors
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | Simple Authentication
30 |
31 | Make login our problem. Not yours.
32 |
33 |
34 |
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.
35 |
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.
36 |
37 |
38 |
39 |
49 |
50 |
51 |
65 |
66 |
67 |
77 |
78 |
79 |
93 |
94 |
95 | ---
96 |
97 | Status:
98 | [](https://travis-ci.org/jaredhanson/passport)
99 | [](https://coveralls.io/r/jaredhanson/passport)
100 | [](https://david-dm.org/jaredhanson/passport)
101 |
102 |
103 | ## Install
104 |
105 | ```
106 | $ npm install passport
107 | ```
108 |
109 | ## Usage
110 |
111 | #### Strategies
112 |
113 | Passport uses the concept of strategies to authenticate requests. Strategies
114 | can range from verifying username and password credentials, delegated
115 | authentication using [OAuth](http://oauth.net/) (for example, via [Facebook](http://www.facebook.com/)
116 | or [Twitter](http://twitter.com/)), or federated authentication using [OpenID](http://openid.net/).
117 |
118 | Before authenticating requests, the strategy (or strategies) used by an
119 | application must be configured.
120 |
121 | ```javascript
122 | passport.use(new LocalStrategy(
123 | function(username, password, done) {
124 | User.findOne({ username: username }, function (err, user) {
125 | if (err) { return done(err); }
126 | if (!user) { return done(null, false); }
127 | if (!user.verifyPassword(password)) { return done(null, false); }
128 | return done(null, user);
129 | });
130 | }
131 | ));
132 | ```
133 |
134 | There are 480+ strategies. Find the ones you want at: [passportjs.org](http://passportjs.org)
135 |
136 | #### Sessions
137 |
138 | Passport will maintain persistent login sessions. In order for persistent
139 | sessions to work, the authenticated user must be serialized to the session, and
140 | deserialized when subsequent requests are made.
141 |
142 | Passport does not impose any restrictions on how your user records are stored.
143 | Instead, you provide functions to Passport which implements the necessary
144 | serialization and deserialization logic. In a typical application, this will be
145 | as simple as serializing the user ID, and finding the user by ID when
146 | deserializing.
147 |
148 | ```javascript
149 | passport.serializeUser(function(user, done) {
150 | done(null, user.id);
151 | });
152 |
153 | passport.deserializeUser(function(id, done) {
154 | User.findById(id, function (err, user) {
155 | done(err, user);
156 | });
157 | });
158 | ```
159 |
160 | #### Middleware
161 |
162 | To use Passport in an [Express](http://expressjs.com/) or
163 | [Connect](http://senchalabs.github.com/connect/)-based application, configure it
164 | with the required `passport.initialize()` middleware. If your application uses
165 | persistent login sessions (recommended, but not required), `passport.session()`
166 | middleware must also be used.
167 |
168 | ```javascript
169 | var app = express();
170 | app.use(require('serve-static')(__dirname + '/../../public'));
171 | app.use(require('cookie-parser')());
172 | app.use(require('body-parser').urlencoded({ extended: true }));
173 | app.use(require('express-session')({ secret: 'keyboard cat', resave: true, saveUninitialized: true }));
174 | app.use(passport.initialize());
175 | app.use(passport.session());
176 | ```
177 |
178 | #### Authenticate Requests
179 |
180 | Passport provides an `authenticate()` function, which is used as route
181 | middleware to authenticate requests.
182 |
183 | ```javascript
184 | app.post('/login',
185 | passport.authenticate('local', { failureRedirect: '/login' }),
186 | function(req, res) {
187 | res.redirect('/');
188 | });
189 | ```
190 |
191 | ## Strategies
192 |
193 | Passport has a comprehensive set of **over 480** authentication strategies
194 | covering social networking, enterprise integration, API services, and more.
195 |
196 | ## Search all strategies
197 |
198 | There is a **Strategy Search** at [passportjs.org](http://passportjs.org)
199 |
200 | The following table lists commonly used strategies:
201 |
202 | |Strategy | Protocol |Developer |
203 | |---------------------------------------------------------------|--------------------------|------------------------------------------------|
204 | |[Local](https://github.com/jaredhanson/passport-local) | HTML form |[Jared Hanson](https://github.com/jaredhanson) |
205 | |[OpenID](https://github.com/jaredhanson/passport-openid) | OpenID |[Jared Hanson](https://github.com/jaredhanson) |
206 | |[BrowserID](https://github.com/jaredhanson/passport-browserid) | BrowserID |[Jared Hanson](https://github.com/jaredhanson) |
207 | |[Facebook](https://github.com/jaredhanson/passport-facebook) | OAuth 2.0 |[Jared Hanson](https://github.com/jaredhanson) |
208 | |[Google](https://github.com/jaredhanson/passport-google) | OpenID |[Jared Hanson](https://github.com/jaredhanson) |
209 | |[Google](https://github.com/jaredhanson/passport-google-oauth) | OAuth / OAuth 2.0 |[Jared Hanson](https://github.com/jaredhanson) |
210 | |[Twitter](https://github.com/jaredhanson/passport-twitter) | OAuth |[Jared Hanson](https://github.com/jaredhanson) |
211 | |[Azure Active Directory](https://github.com/AzureAD/passport-azure-ad) | OAuth 2.0 / OpenID / SAML |[Azure](https://github.com/azuread) |
212 |
213 | ## Examples
214 |
215 | - For a complete, working example, refer to the [example](https://github.com/passport/express-4.x-local-example)
216 | that uses [passport-local](https://github.com/jaredhanson/passport-local).
217 | - **Local Strategy**: Refer to the following tutorials for setting up user authentication via LocalStrategy (`passport-local`):
218 | - Mongo
219 | - 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)
220 | - 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)
221 | - Postgres
222 | - [Tutorial](http://mherman.org/blog/2015/01/31/local-authentication-with-passport-and-express-4/) / [working example](https://github.com/mjhea0/passport-local-express4)
223 | - **Social Authentication**: Refer to the following tutorials for setting up various social authentication strategies:
224 | - Express v3x - [Tutorial](http://mherman.org/blog/2013/11/10/social-authentication-with-passport-dot-js/) / [working example](https://github.com/mjhea0/passport-examples)
225 | - 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)
226 |
227 | ## Related Modules
228 |
229 | - [Locomotive](https://github.com/jaredhanson/locomotive) — Powerful MVC web framework
230 | - [OAuthorize](https://github.com/jaredhanson/oauthorize) — OAuth service provider toolkit
231 | - [OAuth2orize](https://github.com/jaredhanson/oauth2orize) — OAuth 2.0 authorization server toolkit
232 | - [connect-ensure-login](https://github.com/jaredhanson/connect-ensure-login) — middleware to ensure login sessions
233 |
234 | The [modules](https://github.com/jaredhanson/passport/wiki/Modules) page on the
235 | [wiki](https://github.com/jaredhanson/passport/wiki) lists other useful modules
236 | that build upon or integrate with Passport.
237 |
238 | ## License
239 |
240 | [The MIT License](http://opensource.org/licenses/MIT)
241 |
242 | Copyright (c) 2011-2021 Jared Hanson <[https://www.jaredhanson.me/](https://www.jaredhanson.me/)>
243 |
--------------------------------------------------------------------------------
/SPONSORS.md:
--------------------------------------------------------------------------------
1 | ## Gold Sponsors
2 |
3 | [](https://workos.com/)
4 |
5 | [](https://snyk.io/)
6 |
7 | ## Sponsors
8 |
9 | - [CodePilot.ai](https://codepilot.ai/)
10 | - [Jeremy Combs](https://github.com/jmcombs)
11 | - [Gadget](https://gadget.dev/)
12 | - Kelly Burke
13 | - [Matt Miller](https://mmiller.me/)
14 |
15 | ## Past Sponsors
16 |
17 | - [LoginRadius](https://www.loginradius.com/)
18 |
--------------------------------------------------------------------------------
/etc/jsdoc.json:
--------------------------------------------------------------------------------
1 | {
2 | "plugins": ["plugins/markdown"]
3 | }
4 |
--------------------------------------------------------------------------------
/lib/authenticator.js:
--------------------------------------------------------------------------------
1 | // Module dependencies.
2 | var SessionStrategy = require('./strategies/session')
3 | , SessionManager = require('./sessionmanager');
4 |
5 |
6 | /**
7 | * Create a new `Authenticator` object.
8 | *
9 | * @public
10 | * @class
11 | */
12 | function Authenticator() {
13 | this._key = 'passport';
14 | this._strategies = {};
15 | this._serializers = [];
16 | this._deserializers = [];
17 | this._infoTransformers = [];
18 | this._framework = null;
19 |
20 | this.init();
21 | }
22 |
23 | /**
24 | * Initialize authenticator.
25 | *
26 | * Initializes the `Authenticator` instance by creating the default `{@link SessionManager}`,
27 | * {@link Authenticator#use `use()`}'ing the default `{@link SessionStrategy}`, and
28 | * adapting it to work as {@link https://github.com/senchalabs/connect#readme Connect}-style
29 | * middleware, which is also compatible with {@link https://expressjs.com/ Express}.
30 | *
31 | * @private
32 | */
33 | Authenticator.prototype.init = function() {
34 | this.framework(require('./framework/connect')());
35 | this.use(new SessionStrategy({ key: this._key }, this.deserializeUser.bind(this)));
36 | this._sm = new SessionManager({ key: this._key }, this.serializeUser.bind(this));
37 | };
38 |
39 | /**
40 | * Register a strategy for later use when authenticating requests. The name
41 | * with which the strategy is registered is passed to {@link Authenticator#authenticate `authenticate()`}.
42 | *
43 | * @public
44 | * @param {string} [name=strategy.name] - Name of the strategy. When specified,
45 | * this value overrides the strategy's name.
46 | * @param {Strategy} strategy - Authentication strategy.
47 | * @returns {this}
48 | *
49 | * @example Register strategy.
50 | * passport.use(new GoogleStrategy(...));
51 | *
52 | * @example Register strategy and override name.
53 | * passport.use('password', new LocalStrategy(function(username, password, cb) {
54 | * // ...
55 | * }));
56 | */
57 | Authenticator.prototype.use = function(name, strategy) {
58 | if (!strategy) {
59 | strategy = name;
60 | name = strategy.name;
61 | }
62 | if (!name) { throw new Error('Authentication strategies must have a name'); }
63 |
64 | this._strategies[name] = strategy;
65 | return this;
66 | };
67 |
68 | /**
69 | * Deregister a strategy that was previously registered with the given name.
70 | *
71 | * In a typical application, the necessary authentication strategies are
72 | * registered when initializing the app and, once registered, are always
73 | * available. As such, it is typically not necessary to call this function.
74 | *
75 | * @public
76 | * @param {string} name - Name of the strategy.
77 | * @returns {this}
78 | *
79 | * @example
80 | * passport.unuse('acme');
81 | */
82 | Authenticator.prototype.unuse = function(name) {
83 | delete this._strategies[name];
84 | return this;
85 | };
86 |
87 | /**
88 | * Adapt this `Authenticator` to work with a specific framework.
89 | *
90 | * By default, Passport works as {@link https://github.com/senchalabs/connect#readme Connect}-style
91 | * middleware, which makes it compatible with {@link https://expressjs.com/ Express}.
92 | * For any app built using Express, there is no need to call this function.
93 | *
94 | * @public
95 | * @param {Object} fw
96 | * @returns {this}
97 | */
98 | Authenticator.prototype.framework = function(fw) {
99 | this._framework = fw;
100 | return this;
101 | };
102 |
103 | /**
104 | * Create initialization middleware.
105 | *
106 | * Returns middleware that initializes Passport to authenticate requests.
107 | *
108 | * As of v0.6.x, it is typically no longer necessary to use this middleware. It
109 | * exists for compatiblity with apps built using previous versions of Passport,
110 | * in which this middleware was necessary.
111 | *
112 | * The primary exception to the above guidance is when using strategies that
113 | * depend directly on `passport@0.4.x` or earlier. These earlier versions of
114 | * Passport monkeypatch Node.js `http.IncomingMessage` in a way that expects
115 | * certain Passport-specific properties to be available. This middleware
116 | * provides a compatibility layer for this situation.
117 | *
118 | * @public
119 | * @param {Object} [options]
120 | * @param {string} [options.userProperty='user'] - Determines what property on
121 | * `req` will be set to the authenticated user object.
122 | * @param {boolean} [options.compat=true] - When `true`, enables a compatibility
123 | * layer for packages that depend on `passport@0.4.x` or earlier.
124 | * @returns {function}
125 | *
126 | * @example
127 | * app.use(passport.initialize());
128 | */
129 | Authenticator.prototype.initialize = function(options) {
130 | options = options || {};
131 | return this._framework.initialize(this, options);
132 | };
133 |
134 | /**
135 | * Create authentication middleware.
136 | *
137 | * Returns middleware that authenticates the request by applying the given
138 | * strategy (or strategies).
139 | *
140 | * Examples:
141 | *
142 | * passport.authenticate('local', function(err, user) {
143 | * if (!user) { return res.redirect('/login'); }
144 | * res.end('Authenticated!');
145 | * })(req, res);
146 | *
147 | * @public
148 | * @param {string|string[]|Strategy} strategy
149 | * @param {Object} [options]
150 | * @param {boolean} [options.session=true]
151 | * @param {boolean} [options.keepSessionInfo=false]
152 | * @param {string} [options.failureRedirect]
153 | * @param {boolean|string|Object} [options.failureFlash=false]
154 | * @param {boolean|string} [options.failureMessage=false]
155 | * @param {boolean|string|Object} [options.successFlash=false]
156 | * @param {string} [options.successReturnToOrRedirect]
157 | * @param {string} [options.successRedirect]
158 | * @param {boolean|string} [options.successMessage=false]
159 | * @param {boolean} [options.failWithError=false]
160 | * @param {string} [options.assignProperty]
161 | * @param {boolean} [options.authInfo=true]
162 | * @param {function} [callback]
163 | * @returns {function}
164 | *
165 | * @example Authenticate username and password submitted via HTML form.
166 | * app.get('/login/password', passport.authenticate('local', { successRedirect: '/', failureRedirect: '/login' }));
167 | *
168 | * @example Authenticate bearer token used to access an API resource.
169 | * app.get('/api/resource', passport.authenticate('bearer', { session: false }));
170 | */
171 | Authenticator.prototype.authenticate = function(strategy, options, callback) {
172 | return this._framework.authenticate(this, strategy, options, callback);
173 | };
174 |
175 | /**
176 | * Create third-party service authorization middleware.
177 | *
178 | * Returns middleware that will authorize a connection to a third-party service.
179 | *
180 | * This middleware is identical to using {@link Authenticator#authenticate `authenticate()`}
181 | * middleware with the `assignProperty` option set to `'account'`. This is
182 | * useful when a user is already authenticated (for example, using a username
183 | * and password) and they want to connect their account with a third-party
184 | * service.
185 | *
186 | * In this scenario, the user's third-party account will be set at
187 | * `req.account`, and the existing `req.user` and login session data will be
188 | * be left unmodified. A route handler can then link the third-party account to
189 | * the existing local account.
190 | *
191 | * All arguments to this function behave identically to those accepted by
192 | * `{@link Authenticator#authenticate}`.
193 | *
194 | * @public
195 | * @param {string|string[]|Strategy} strategy
196 | * @param {Object} [options]
197 | * @param {function} [callback]
198 | * @returns {function}
199 | *
200 | * @example
201 | * app.get('/oauth/callback/twitter', passport.authorize('twitter'));
202 | */
203 | Authenticator.prototype.authorize = function(strategy, options, callback) {
204 | options = options || {};
205 | options.assignProperty = 'account';
206 |
207 | var fn = this._framework.authorize || this._framework.authenticate;
208 | return fn(this, strategy, options, callback);
209 | };
210 |
211 | /**
212 | * Middleware that will restore login state from a session.
213 | *
214 | * Web applications typically use sessions to maintain login state between
215 | * requests. For example, a user will authenticate by entering credentials into
216 | * a form which is submitted to the server. If the credentials are valid, a
217 | * login session is established by setting a cookie containing a session
218 | * identifier in the user's web browser. The web browser will send this cookie
219 | * in subsequent requests to the server, allowing a session to be maintained.
220 | *
221 | * If sessions are being utilized, and a login session has been established,
222 | * this middleware will populate `req.user` with the current user.
223 | *
224 | * Note that sessions are not strictly required for Passport to operate.
225 | * However, as a general rule, most web applications will make use of sessions.
226 | * An exception to this rule would be an API server, which expects each HTTP
227 | * request to provide credentials in an Authorization header.
228 | *
229 | * Examples:
230 | *
231 | * app.use(connect.cookieParser());
232 | * app.use(connect.session({ secret: 'keyboard cat' }));
233 | * app.use(passport.initialize());
234 | * app.use(passport.session());
235 | *
236 | * Options:
237 | * - `pauseStream` Pause the request stream before deserializing the user
238 | * object from the session. Defaults to _false_. Should
239 | * be set to true in cases where middleware consuming the
240 | * request body is configured after passport and the
241 | * deserializeUser method is asynchronous.
242 | *
243 | * @param {Object} options
244 | * @return {Function} middleware
245 | * @api public
246 | */
247 | Authenticator.prototype.session = function(options) {
248 | return this.authenticate('session', options);
249 | };
250 |
251 | // TODO: Make session manager pluggable
252 | /*
253 | Authenticator.prototype.sessionManager = function(mgr) {
254 | this._sm = mgr;
255 | return this;
256 | }
257 | */
258 |
259 | /**
260 | * Registers a function used to serialize user objects into the session.
261 | *
262 | * Examples:
263 | *
264 | * passport.serializeUser(function(user, done) {
265 | * done(null, user.id);
266 | * });
267 | *
268 | * @api public
269 | */
270 | Authenticator.prototype.serializeUser = function(fn, req, done) {
271 | if (typeof fn === 'function') {
272 | return this._serializers.push(fn);
273 | }
274 |
275 | // private implementation that traverses the chain of serializers, attempting
276 | // to serialize a user
277 | var user = fn;
278 |
279 | // For backwards compatibility
280 | if (typeof req === 'function') {
281 | done = req;
282 | req = undefined;
283 | }
284 |
285 | var stack = this._serializers;
286 | (function pass(i, err, obj) {
287 | // serializers use 'pass' as an error to skip processing
288 | if ('pass' === err) {
289 | err = undefined;
290 | }
291 | // an error or serialized object was obtained, done
292 | if (err || obj || obj === 0) { return done(err, obj); }
293 |
294 | var layer = stack[i];
295 | if (!layer) {
296 | return done(new Error('Failed to serialize user into session'));
297 | }
298 |
299 |
300 | function serialized(e, o) {
301 | pass(i + 1, e, o);
302 | }
303 |
304 | try {
305 | var arity = layer.length;
306 | if (arity == 3) {
307 | layer(req, user, serialized);
308 | } else {
309 | layer(user, serialized);
310 | }
311 | } catch(e) {
312 | return done(e);
313 | }
314 | })(0);
315 | };
316 |
317 | /**
318 | * Registers a function used to deserialize user objects out of the session.
319 | *
320 | * Examples:
321 | *
322 | * passport.deserializeUser(function(id, done) {
323 | * User.findById(id, function (err, user) {
324 | * done(err, user);
325 | * });
326 | * });
327 | *
328 | * @api public
329 | */
330 | Authenticator.prototype.deserializeUser = function(fn, req, done) {
331 | if (typeof fn === 'function') {
332 | return this._deserializers.push(fn);
333 | }
334 |
335 | // private implementation that traverses the chain of deserializers,
336 | // attempting to deserialize a user
337 | var obj = fn;
338 |
339 | // For backwards compatibility
340 | if (typeof req === 'function') {
341 | done = req;
342 | req = undefined;
343 | }
344 |
345 | var stack = this._deserializers;
346 | (function pass(i, err, user) {
347 | // deserializers use 'pass' as an error to skip processing
348 | if ('pass' === err) {
349 | err = undefined;
350 | }
351 | // an error or deserialized user was obtained, done
352 | if (err || user) { return done(err, user); }
353 | // a valid user existed when establishing the session, but that user has
354 | // since been removed
355 | if (user === null || user === false) { return done(null, false); }
356 |
357 | var layer = stack[i];
358 | if (!layer) {
359 | return done(new Error('Failed to deserialize user out of session'));
360 | }
361 |
362 |
363 | function deserialized(e, u) {
364 | pass(i + 1, e, u);
365 | }
366 |
367 | try {
368 | var arity = layer.length;
369 | if (arity == 3) {
370 | layer(req, obj, deserialized);
371 | } else {
372 | layer(obj, deserialized);
373 | }
374 | } catch(e) {
375 | return done(e);
376 | }
377 | })(0);
378 | };
379 |
380 | /**
381 | * Registers a function used to transform auth info.
382 | *
383 | * In some circumstances authorization details are contained in authentication
384 | * credentials or loaded as part of verification.
385 | *
386 | * For example, when using bearer tokens for API authentication, the tokens may
387 | * encode (either directly or indirectly in a database), details such as scope
388 | * of access or the client to which the token was issued.
389 | *
390 | * Such authorization details should be enforced separately from authentication.
391 | * Because Passport deals only with the latter, this is the responsiblity of
392 | * middleware or routes further along the chain. However, it is not optimal to
393 | * decode the same data or execute the same database query later. To avoid
394 | * this, Passport accepts optional `info` along with the authenticated `user`
395 | * in a strategy's `success()` action. This info is set at `req.authInfo`,
396 | * where said later middlware or routes can access it.
397 | *
398 | * Optionally, applications can register transforms to proccess this info,
399 | * which take effect prior to `req.authInfo` being set. This is useful, for
400 | * example, when the info contains a client ID. The transform can load the
401 | * client from the database and include the instance in the transformed info,
402 | * allowing the full set of client properties to be convieniently accessed.
403 | *
404 | * If no transforms are registered, `info` supplied by the strategy will be left
405 | * unmodified.
406 | *
407 | * Examples:
408 | *
409 | * passport.transformAuthInfo(function(info, done) {
410 | * Client.findById(info.clientID, function (err, client) {
411 | * info.client = client;
412 | * done(err, info);
413 | * });
414 | * });
415 | *
416 | * @api public
417 | */
418 | Authenticator.prototype.transformAuthInfo = function(fn, req, done) {
419 | if (typeof fn === 'function') {
420 | return this._infoTransformers.push(fn);
421 | }
422 |
423 | // private implementation that traverses the chain of transformers,
424 | // attempting to transform auth info
425 | var info = fn;
426 |
427 | // For backwards compatibility
428 | if (typeof req === 'function') {
429 | done = req;
430 | req = undefined;
431 | }
432 |
433 | var stack = this._infoTransformers;
434 | (function pass(i, err, tinfo) {
435 | // transformers use 'pass' as an error to skip processing
436 | if ('pass' === err) {
437 | err = undefined;
438 | }
439 | // an error or transformed info was obtained, done
440 | if (err || tinfo) { return done(err, tinfo); }
441 |
442 | var layer = stack[i];
443 | if (!layer) {
444 | // if no transformers are registered (or they all pass), the default
445 | // behavior is to use the un-transformed info as-is
446 | return done(null, info);
447 | }
448 |
449 |
450 | function transformed(e, t) {
451 | pass(i + 1, e, t);
452 | }
453 |
454 | try {
455 | var arity = layer.length;
456 | if (arity == 1) {
457 | // sync
458 | var t = layer(info);
459 | transformed(null, t);
460 | } else if (arity == 3) {
461 | layer(req, info, transformed);
462 | } else {
463 | layer(info, transformed);
464 | }
465 | } catch(e) {
466 | return done(e);
467 | }
468 | })(0);
469 | };
470 |
471 | /**
472 | * Return strategy with given `name`.
473 | *
474 | * @param {String} name
475 | * @return {Strategy}
476 | * @api private
477 | */
478 | Authenticator.prototype._strategy = function(name) {
479 | return this._strategies[name];
480 | };
481 |
482 |
483 | /**
484 | * Expose `Authenticator`.
485 | */
486 | module.exports = Authenticator;
487 |
--------------------------------------------------------------------------------
/lib/errors/authenticationerror.js:
--------------------------------------------------------------------------------
1 | /**
2 | * `AuthenticationError` error.
3 | *
4 | * @constructor
5 | * @api private
6 | */
7 | function AuthenticationError(message, status) {
8 | Error.call(this);
9 | Error.captureStackTrace(this, arguments.callee);
10 | this.name = 'AuthenticationError';
11 | this.message = message;
12 | this.status = status || 401;
13 | }
14 |
15 | // Inherit from `Error`.
16 | AuthenticationError.prototype.__proto__ = Error.prototype;
17 |
18 |
19 | // Expose constructor.
20 | module.exports = AuthenticationError;
21 |
--------------------------------------------------------------------------------
/lib/framework/connect.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Module dependencies.
3 | */
4 | var initialize = require('../middleware/initialize')
5 | , authenticate = require('../middleware/authenticate');
6 |
7 | /**
8 | * Framework support for Connect/Express.
9 | *
10 | * This module provides support for using Passport with Express. It exposes
11 | * middleware that conform to the `fn(req, res, next)` signature.
12 | *
13 | * @return {Object}
14 | * @api protected
15 | */
16 | exports = module.exports = function() {
17 |
18 | return {
19 | initialize: initialize,
20 | authenticate: authenticate
21 | };
22 | };
23 |
--------------------------------------------------------------------------------
/lib/http/request.js:
--------------------------------------------------------------------------------
1 | var req = exports = module.exports = {};
2 |
3 | /**
4 | * Initiate a login session for `user`.
5 | *
6 | * Options:
7 | * - `session` Save login state in session, defaults to _true_
8 | *
9 | * Examples:
10 | *
11 | * req.logIn(user, { session: false });
12 | *
13 | * req.logIn(user, function(err) {
14 | * if (err) { throw err; }
15 | * // session saved
16 | * });
17 | *
18 | * @param {User} user
19 | * @param {Object} options
20 | * @param {Function} done
21 | * @api public
22 | */
23 | req.login =
24 | req.logIn = function(user, options, done) {
25 | if (typeof options == 'function') {
26 | done = options;
27 | options = {};
28 | }
29 | options = options || {};
30 |
31 | var property = this._userProperty || 'user';
32 | var session = (options.session === undefined) ? true : options.session;
33 |
34 | this[property] = user;
35 | if (session && this._sessionManager) {
36 | if (typeof done != 'function') { throw new Error('req#login requires a callback function'); }
37 |
38 | var self = this;
39 | this._sessionManager.logIn(this, user, options, function(err) {
40 | if (err) { self[property] = null; return done(err); }
41 | done();
42 | });
43 | } else {
44 | done && done();
45 | }
46 | };
47 |
48 | /**
49 | * Terminate an existing login session.
50 | *
51 | * @api public
52 | */
53 | req.logout =
54 | req.logOut = function(options, done) {
55 | if (typeof options == 'function') {
56 | done = options;
57 | options = {};
58 | }
59 | options = options || {};
60 |
61 | var property = this._userProperty || 'user';
62 |
63 | this[property] = null;
64 | if (this._sessionManager) {
65 | if (typeof done != 'function') { throw new Error('req#logout requires a callback function'); }
66 |
67 | this._sessionManager.logOut(this, options, done);
68 | } else {
69 | done && done();
70 | }
71 | };
72 |
73 | /**
74 | * Test if request is authenticated.
75 | *
76 | * @return {Boolean}
77 | * @api public
78 | */
79 | req.isAuthenticated = function() {
80 | var property = this._userProperty || 'user';
81 | return (this[property]) ? true : false;
82 | };
83 |
84 | /**
85 | * Test if request is unauthenticated.
86 | *
87 | * @return {Boolean}
88 | * @api public
89 | */
90 | req.isUnauthenticated = function() {
91 | return !this.isAuthenticated();
92 | };
93 |
--------------------------------------------------------------------------------
/lib/index.js:
--------------------------------------------------------------------------------
1 | // Module dependencies.
2 | var Passport = require('./authenticator')
3 | , SessionStrategy = require('./strategies/session');
4 |
5 |
6 | /**
7 | * Export default singleton.
8 | *
9 | * @api public
10 | */
11 | exports = module.exports = new Passport();
12 |
13 | /**
14 | * Expose constructors.
15 | */
16 | exports.Passport =
17 | exports.Authenticator = Passport;
18 | exports.Strategy = require('passport-strategy');
19 |
20 | /*
21 | * Expose strategies.
22 | */
23 | exports.strategies = {};
24 | exports.strategies.SessionStrategy = SessionStrategy;
25 |
--------------------------------------------------------------------------------
/lib/middleware/authenticate.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Module dependencies.
3 | */
4 | var http = require('http')
5 | , IncomingMessageExt = require('../http/request')
6 | , AuthenticationError = require('../errors/authenticationerror');
7 |
8 |
9 | /**
10 | * Authenticates requests.
11 | *
12 | * Applies the `name`ed strategy (or strategies) to the incoming request, in
13 | * order to authenticate the request. If authentication is successful, the user
14 | * will be logged in and populated at `req.user` and a session will be
15 | * established by default. If authentication fails, an unauthorized response
16 | * will be sent.
17 | *
18 | * Options:
19 | * - `session` Save login state in session, defaults to _true_
20 | * - `successRedirect` After successful login, redirect to given URL
21 | * - `successMessage` True to store success message in
22 | * req.session.messages, or a string to use as override
23 | * message for success.
24 | * - `successFlash` True to flash success messages or a string to use as a flash
25 | * message for success (overrides any from the strategy itself).
26 | * - `failureRedirect` After failed login, redirect to given URL
27 | * - `failureMessage` True to store failure message in
28 | * req.session.messages, or a string to use as override
29 | * message for failure.
30 | * - `failureFlash` True to flash failure messages or a string to use as a flash
31 | * message for failures (overrides any from the strategy itself).
32 | * - `assignProperty` Assign the object provided by the verify callback to given property
33 | *
34 | * An optional `callback` can be supplied to allow the application to override
35 | * the default manner in which authentication attempts are handled. The
36 | * callback has the following signature, where `user` will be set to the
37 | * authenticated user on a successful authentication attempt, or `false`
38 | * otherwise. An optional `info` argument will be passed, containing additional
39 | * details provided by the strategy's verify callback - this could be information about
40 | * a successful authentication or a challenge message for a failed authentication.
41 | * An optional `status` argument will be passed when authentication fails - this could
42 | * be a HTTP response code for a remote authentication failure or similar.
43 | *
44 | * app.get('/protected', function(req, res, next) {
45 | * passport.authenticate('local', function(err, user, info, status) {
46 | * if (err) { return next(err) }
47 | * if (!user) { return res.redirect('/signin') }
48 | * res.redirect('/account');
49 | * })(req, res, next);
50 | * });
51 | *
52 | * Note that if a callback is supplied, it becomes the application's
53 | * responsibility to log-in the user, establish a session, and otherwise perform
54 | * the desired operations.
55 | *
56 | * Examples:
57 | *
58 | * passport.authenticate('local', { successRedirect: '/', failureRedirect: '/login' });
59 | *
60 | * passport.authenticate('basic', { session: false });
61 | *
62 | * passport.authenticate('twitter');
63 | *
64 | * @param {Strategy|String|Array} name
65 | * @param {Object} options
66 | * @param {Function} callback
67 | * @return {Function}
68 | * @api public
69 | */
70 | module.exports = function authenticate(passport, name, options, callback) {
71 | if (typeof options == 'function') {
72 | callback = options;
73 | options = {};
74 | }
75 | options = options || {};
76 |
77 | var multi = true;
78 |
79 | // Cast `name` to an array, allowing authentication to pass through a chain of
80 | // strategies. The first strategy to succeed, redirect, or error will halt
81 | // the chain. Authentication failures will proceed through each strategy in
82 | // series, ultimately failing if all strategies fail.
83 | //
84 | // This is typically used on API endpoints to allow clients to authenticate
85 | // using their preferred choice of Basic, Digest, token-based schemes, etc.
86 | // It is not feasible to construct a chain of multiple strategies that involve
87 | // redirection (for example both Facebook and Twitter), since the first one to
88 | // redirect will halt the chain.
89 | if (!Array.isArray(name)) {
90 | name = [ name ];
91 | multi = false;
92 | }
93 |
94 | return function authenticate(req, res, next) {
95 | req.login =
96 | req.logIn = req.logIn || IncomingMessageExt.logIn;
97 | req.logout =
98 | req.logOut = req.logOut || IncomingMessageExt.logOut;
99 | req.isAuthenticated = req.isAuthenticated || IncomingMessageExt.isAuthenticated;
100 | req.isUnauthenticated = req.isUnauthenticated || IncomingMessageExt.isUnauthenticated;
101 |
102 | req._sessionManager = passport._sm;
103 |
104 | // accumulator for failures from each strategy in the chain
105 | var failures = [];
106 |
107 | function allFailed() {
108 | if (callback) {
109 | if (!multi) {
110 | return callback(null, false, failures[0].challenge, failures[0].status);
111 | } else {
112 | var challenges = failures.map(function(f) { return f.challenge; });
113 | var statuses = failures.map(function(f) { return f.status; });
114 | return callback(null, false, challenges, statuses);
115 | }
116 | }
117 |
118 | // Strategies are ordered by priority. For the purpose of flashing a
119 | // message, the first failure will be displayed.
120 | var failure = failures[0] || {}
121 | , challenge = failure.challenge || {}
122 | , msg;
123 |
124 | if (options.failureFlash) {
125 | var flash = options.failureFlash;
126 | if (typeof flash == 'string') {
127 | flash = { type: 'error', message: flash };
128 | }
129 | flash.type = flash.type || 'error';
130 |
131 | var type = flash.type || challenge.type || 'error';
132 | msg = flash.message || challenge.message || challenge;
133 | if (typeof msg == 'string') {
134 | req.flash(type, msg);
135 | }
136 | }
137 | if (options.failureMessage) {
138 | msg = options.failureMessage;
139 | if (typeof msg == 'boolean') {
140 | msg = challenge.message || challenge;
141 | }
142 | if (typeof msg == 'string') {
143 | req.session.messages = req.session.messages || [];
144 | req.session.messages.push(msg);
145 | }
146 | }
147 | if (options.failureRedirect) {
148 | return res.redirect(options.failureRedirect);
149 | }
150 |
151 | // When failure handling is not delegated to the application, the default
152 | // is to respond with 401 Unauthorized. Note that the WWW-Authenticate
153 | // header will be set according to the strategies in use (see
154 | // actions#fail). If multiple strategies failed, each of their challenges
155 | // will be included in the response.
156 | var rchallenge = []
157 | , rstatus, status;
158 |
159 | for (var j = 0, len = failures.length; j < len; j++) {
160 | failure = failures[j];
161 | challenge = failure.challenge;
162 | status = failure.status;
163 |
164 | rstatus = rstatus || status;
165 | if (typeof challenge == 'string') {
166 | rchallenge.push(challenge);
167 | }
168 | }
169 |
170 | res.statusCode = rstatus || 401;
171 | if (res.statusCode == 401 && rchallenge.length) {
172 | res.setHeader('WWW-Authenticate', rchallenge);
173 | }
174 | if (options.failWithError) {
175 | return next(new AuthenticationError(http.STATUS_CODES[res.statusCode], rstatus));
176 | }
177 | res.end(http.STATUS_CODES[res.statusCode]);
178 | }
179 |
180 | (function attempt(i) {
181 | var layer = name[i];
182 | // If no more strategies exist in the chain, authentication has failed.
183 | if (!layer) { return allFailed(); }
184 |
185 | // Get the strategy, which will be used as prototype from which to create
186 | // a new instance. Action functions will then be bound to the strategy
187 | // within the context of the HTTP request/response pair.
188 | var strategy, prototype;
189 | if (typeof layer.authenticate == 'function') {
190 | strategy = layer;
191 | } else {
192 | prototype = passport._strategy(layer);
193 | if (!prototype) { return next(new Error('Unknown authentication strategy "' + layer + '"')); }
194 |
195 | strategy = Object.create(prototype);
196 | }
197 |
198 |
199 | // ----- BEGIN STRATEGY AUGMENTATION -----
200 | // Augment the new strategy instance with action functions. These action
201 | // functions are bound via closure the the request/response pair. The end
202 | // goal of the strategy is to invoke *one* of these action methods, in
203 | // order to indicate successful or failed authentication, redirect to a
204 | // third-party identity provider, etc.
205 |
206 | /**
207 | * Authenticate `user`, with optional `info`.
208 | *
209 | * Strategies should call this function to successfully authenticate a
210 | * user. `user` should be an object supplied by the application after it
211 | * has been given an opportunity to verify credentials. `info` is an
212 | * optional argument containing additional user information. This is
213 | * useful for third-party authentication strategies to pass profile
214 | * details.
215 | *
216 | * @param {Object} user
217 | * @param {Object} info
218 | * @api public
219 | */
220 | strategy.success = function(user, info) {
221 | if (callback) {
222 | return callback(null, user, info);
223 | }
224 |
225 | info = info || {};
226 | var msg;
227 |
228 | if (options.successFlash) {
229 | var flash = options.successFlash;
230 | if (typeof flash == 'string') {
231 | flash = { type: 'success', message: flash };
232 | }
233 | flash.type = flash.type || 'success';
234 |
235 | var type = flash.type || info.type || 'success';
236 | msg = flash.message || info.message || info;
237 | if (typeof msg == 'string') {
238 | req.flash(type, msg);
239 | }
240 | }
241 | if (options.successMessage) {
242 | msg = options.successMessage;
243 | if (typeof msg == 'boolean') {
244 | msg = info.message || info;
245 | }
246 | if (typeof msg == 'string') {
247 | req.session.messages = req.session.messages || [];
248 | req.session.messages.push(msg);
249 | }
250 | }
251 | if (options.assignProperty) {
252 | req[options.assignProperty] = user;
253 | if (options.authInfo !== false) {
254 | passport.transformAuthInfo(info, req, function(err, tinfo) {
255 | if (err) { return next(err); }
256 | req.authInfo = tinfo;
257 | next();
258 | });
259 | } else {
260 | next();
261 | }
262 | return;
263 | }
264 |
265 | req.logIn(user, options, function(err) {
266 | if (err) { return next(err); }
267 |
268 | function complete() {
269 | if (options.successReturnToOrRedirect) {
270 | var url = options.successReturnToOrRedirect;
271 | if (req.session && req.session.returnTo) {
272 | url = req.session.returnTo;
273 | delete req.session.returnTo;
274 | }
275 | return res.redirect(url);
276 | }
277 | if (options.successRedirect) {
278 | return res.redirect(options.successRedirect);
279 | }
280 | next();
281 | }
282 |
283 | if (options.authInfo !== false) {
284 | passport.transformAuthInfo(info, req, function(err, tinfo) {
285 | if (err) { return next(err); }
286 | req.authInfo = tinfo;
287 | complete();
288 | });
289 | } else {
290 | complete();
291 | }
292 | });
293 | };
294 |
295 | /**
296 | * Fail authentication, with optional `challenge` and `status`, defaulting
297 | * to 401.
298 | *
299 | * Strategies should call this function to fail an authentication attempt.
300 | *
301 | * @param {String} challenge
302 | * @param {Number} status
303 | * @api public
304 | */
305 | strategy.fail = function(challenge, status) {
306 | if (typeof challenge == 'number') {
307 | status = challenge;
308 | challenge = undefined;
309 | }
310 |
311 | // push this failure into the accumulator and attempt authentication
312 | // using the next strategy
313 | failures.push({ challenge: challenge, status: status });
314 | attempt(i + 1);
315 | };
316 |
317 | /**
318 | * Redirect to `url` with optional `status`, defaulting to 302.
319 | *
320 | * Strategies should call this function to redirect the user (via their
321 | * user agent) to a third-party website for authentication.
322 | *
323 | * @param {String} url
324 | * @param {Number} status
325 | * @api public
326 | */
327 | strategy.redirect = function(url, status) {
328 | // NOTE: Do not use `res.redirect` from Express, because it can't decide
329 | // what it wants.
330 | //
331 | // Express 2.x: res.redirect(url, status)
332 | // Express 3.x: res.redirect(status, url) -OR- res.redirect(url, status)
333 | // - as of 3.14.0, deprecated warnings are issued if res.redirect(url, status)
334 | // is used
335 | // Express 4.x: res.redirect(status, url)
336 | // - all versions (as of 4.8.7) continue to accept res.redirect(url, status)
337 | // but issue deprecated versions
338 |
339 | res.statusCode = status || 302;
340 | res.setHeader('Location', url);
341 | res.setHeader('Content-Length', '0');
342 | res.end();
343 | };
344 |
345 | /**
346 | * Pass without making a success or fail decision.
347 | *
348 | * Under most circumstances, Strategies should not need to call this
349 | * function. It exists primarily to allow previous authentication state
350 | * to be restored, for example from an HTTP session.
351 | *
352 | * @api public
353 | */
354 | strategy.pass = function() {
355 | next();
356 | };
357 |
358 | /**
359 | * Internal error while performing authentication.
360 | *
361 | * Strategies should call this function when an internal error occurs
362 | * during the process of performing authentication; for example, if the
363 | * user directory is not available.
364 | *
365 | * @param {Error} err
366 | * @api public
367 | */
368 | strategy.error = function(err) {
369 | if (callback) {
370 | return callback(err);
371 | }
372 |
373 | next(err);
374 | };
375 |
376 | // ----- END STRATEGY AUGMENTATION -----
377 |
378 | strategy.authenticate(req, options);
379 | })(0); // attempt
380 | };
381 | };
382 |
--------------------------------------------------------------------------------
/lib/middleware/initialize.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Module dependencies.
3 | */
4 | var IncomingMessageExt = require('../http/request');
5 |
6 |
7 | /**
8 | * Passport initialization.
9 | *
10 | * Intializes Passport for incoming requests, allowing authentication strategies
11 | * to be applied.
12 | *
13 | * If sessions are being utilized, applications must set up Passport with
14 | * functions to serialize a user into and out of a session. For example, a
15 | * common pattern is to serialize just the user ID into the session (due to the
16 | * fact that it is desirable to store the minimum amount of data in a session).
17 | * When a subsequent request arrives for the session, the full User object can
18 | * be loaded from the database by ID.
19 | *
20 | * Note that additional middleware is required to persist login state, so we
21 | * must use the `connect.session()` middleware _before_ `passport.initialize()`.
22 | *
23 | * If sessions are being used, this middleware must be in use by the
24 | * Connect/Express application for Passport to operate. If the application is
25 | * entirely stateless (not using sessions), this middleware is not necessary,
26 | * but its use will not have any adverse impact.
27 | *
28 | * Examples:
29 | *
30 | * app.use(connect.cookieParser());
31 | * app.use(connect.session({ secret: 'keyboard cat' }));
32 | * app.use(passport.initialize());
33 | * app.use(passport.session());
34 | *
35 | * passport.serializeUser(function(user, done) {
36 | * done(null, user.id);
37 | * });
38 | *
39 | * passport.deserializeUser(function(id, done) {
40 | * User.findById(id, function (err, user) {
41 | * done(err, user);
42 | * });
43 | * });
44 | *
45 | * @return {Function}
46 | * @api public
47 | */
48 | module.exports = function initialize(passport, options) {
49 | options = options || {};
50 |
51 | return function initialize(req, res, next) {
52 | req.login =
53 | req.logIn = req.logIn || IncomingMessageExt.logIn;
54 | req.logout =
55 | req.logOut = req.logOut || IncomingMessageExt.logOut;
56 | req.isAuthenticated = req.isAuthenticated || IncomingMessageExt.isAuthenticated;
57 | req.isUnauthenticated = req.isUnauthenticated || IncomingMessageExt.isUnauthenticated;
58 |
59 | req._sessionManager = passport._sm;
60 |
61 | if (options.userProperty) {
62 | req._userProperty = options.userProperty;
63 | }
64 |
65 | var compat = (options.compat === undefined) ? true : options.compat;
66 | if (compat) {
67 | // `passport@0.5.1` [removed][1] all internal use of `req._passport`.
68 | // From the standpoint of this package, this should have been a
69 | // non-breaking change. However, some strategies (such as `passport-azure-ad`)
70 | // depend directly on `passport@0.4.x` or earlier. `require`-ing earlier
71 | // versions of `passport` has the effect of monkeypatching `http.IncomingMessage`
72 | // with `logIn`, `logOut`, `isAuthenticated` and `isUnauthenticated`
73 | // functions that [expect][2] the `req._passport` property to exist.
74 | // Since pre-existing functions on `req` are given [preference][3], this
75 | // results in [issues][4].
76 | //
77 | // The changes here restore the expected properties needed when earlier
78 | // versions of `passport` are `require`-ed. This compatibility mode is
79 | // enabled by default, and can be disabld by simply not `use`-ing `passport.initialize()`
80 | // middleware or setting `compat: false` as an option to the middleware.
81 | //
82 | // An alternative approach to addressing this issue would be to not
83 | // preferentially use pre-existing functions on `req`, but rather always
84 | // overwrite `req.logIn`, etc. with the versions of those functions shiped
85 | // with `authenticate()` middleware. This option should be reconsidered
86 | // in a future major version release.
87 | //
88 | // [1]: https://github.com/jaredhanson/passport/pull/875
89 | // [2]: https://github.com/jaredhanson/passport/blob/v0.4.1/lib/http/request.js
90 | // [3]: https://github.com/jaredhanson/passport/blob/v0.5.1/lib/middleware/authenticate.js#L96
91 | // [4]: https://github.com/jaredhanson/passport/issues/877
92 | passport._userProperty = options.userProperty || 'user';
93 |
94 | req._passport = {};
95 | req._passport.instance = passport;
96 | }
97 |
98 | next();
99 | };
100 | };
101 |
--------------------------------------------------------------------------------
/lib/sessionmanager.js:
--------------------------------------------------------------------------------
1 | var merge = require('utils-merge');
2 |
3 | function SessionManager(options, serializeUser) {
4 | if (typeof options == 'function') {
5 | serializeUser = options;
6 | options = undefined;
7 | }
8 | options = options || {};
9 |
10 | this._key = options.key || 'passport';
11 | this._serializeUser = serializeUser;
12 | }
13 |
14 | SessionManager.prototype.logIn = function(req, user, options, cb) {
15 | if (typeof options == 'function') {
16 | cb = options;
17 | options = {};
18 | }
19 | options = options || {};
20 |
21 | if (!req.session) { return cb(new Error('Login sessions require session support. Did you forget to use `express-session` middleware?')); }
22 |
23 | var self = this;
24 | var prevSession = req.session;
25 |
26 | // regenerate the session, which is good practice to help
27 | // guard against forms of session fixation
28 | req.session.regenerate(function(err) {
29 | if (err) {
30 | return cb(err);
31 | }
32 |
33 | self._serializeUser(user, req, function(err, obj) {
34 | if (err) {
35 | return cb(err);
36 | }
37 | if (options.keepSessionInfo) {
38 | merge(req.session, prevSession);
39 | }
40 | if (!req.session[self._key]) {
41 | req.session[self._key] = {};
42 | }
43 | // store user information in session, typically a user id
44 | req.session[self._key].user = obj;
45 | // save the session before redirection to ensure page
46 | // load does not happen before session is saved
47 | req.session.save(function(err) {
48 | if (err) {
49 | return cb(err);
50 | }
51 | cb();
52 | });
53 | });
54 | });
55 | }
56 |
57 | SessionManager.prototype.logOut = function(req, options, cb) {
58 | if (typeof options == 'function') {
59 | cb = options;
60 | options = {};
61 | }
62 | options = options || {};
63 |
64 | if (!req.session) { return cb(new Error('Login sessions require session support. Did you forget to use `express-session` middleware?')); }
65 |
66 | var self = this;
67 |
68 | // clear the user from the session object and save.
69 | // this will ensure that re-using the old session id
70 | // does not have a logged in user
71 | if (req.session[this._key]) {
72 | delete req.session[this._key].user;
73 | }
74 | var prevSession = req.session;
75 |
76 | req.session.save(function(err) {
77 | if (err) {
78 | return cb(err)
79 | }
80 |
81 | // regenerate the session, which is good practice to help
82 | // guard against forms of session fixation
83 | req.session.regenerate(function(err) {
84 | if (err) {
85 | return cb(err);
86 | }
87 | if (options.keepSessionInfo) {
88 | merge(req.session, prevSession);
89 | }
90 | cb();
91 | });
92 | });
93 | }
94 |
95 |
96 | module.exports = SessionManager;
97 |
--------------------------------------------------------------------------------
/lib/strategies/session.js:
--------------------------------------------------------------------------------
1 | // Module dependencies.
2 | var pause = require('pause')
3 | , util = require('util')
4 | , Strategy = require('passport-strategy');
5 |
6 |
7 | /**
8 | * Create a new `SessionStrategy` object.
9 | *
10 | * An instance of this strategy is automatically used when creating an
11 | * `{@link Authenticator}`. As such, it is typically unnecessary to create an
12 | * instance using this constructor.
13 | *
14 | * @classdesc This `Strategy` authenticates HTTP requests based on the contents
15 | * of session data.
16 | *
17 | * The login session must have been previously initiated, typically upon the
18 | * user interactively logging in using a HTML form. During session initiation,
19 | * the logged-in user's information is persisted to the session so that it can
20 | * be restored on subsequent requests.
21 | *
22 | * Note that this strategy merely restores the authentication state from the
23 | * session, it does not authenticate the session itself. Authenticating the
24 | * underlying session is assumed to have been done by the middleware
25 | * implementing session support. This is typically accomplished by setting a
26 | * signed cookie, and verifying the signature of that cookie on incoming
27 | * requests.
28 | *
29 | * In {@link https://expressjs.com/ Express}-based apps, session support is
30 | * commonly provided by {@link https://github.com/expressjs/session `express-session`}
31 | * or {@link https://github.com/expressjs/cookie-session `cookie-session`}.
32 | *
33 | * @public
34 | * @class
35 | * @augments base.Strategy
36 | * @param {Object} [options]
37 | * @param {string} [options.key='passport'] - Determines what property ("key") on
38 | * the session data where login session data is located. The login
39 | * session is stored and read from `req.session[key]`.
40 | * @param {function} deserializeUser - Function which deserializes user.
41 | */
42 | function SessionStrategy(options, deserializeUser) {
43 | if (typeof options == 'function') {
44 | deserializeUser = options;
45 | options = undefined;
46 | }
47 | options = options || {};
48 |
49 | Strategy.call(this);
50 |
51 | /** The name of the strategy, set to `'session'`.
52 | *
53 | * @type {string}
54 | * @readonly
55 | */
56 | this.name = 'session';
57 | this._key = options.key || 'passport';
58 | this._deserializeUser = deserializeUser;
59 | }
60 |
61 | // Inherit from `passport.Strategy`.
62 | util.inherits(SessionStrategy, Strategy);
63 |
64 | /**
65 | * Authenticate request based on current session data.
66 | *
67 | * When login session data is present in the session, that data will be used to
68 | * restore login state across across requests by calling the deserialize user
69 | * function.
70 | *
71 | * If login session data is not present, the request will be passed to the next
72 | * middleware, rather than failing authentication - which is the behavior of
73 | * most other strategies. This deviation allows session authentication to be
74 | * performed at the application-level, rather than the individual route level,
75 | * while allowing both authenticated and unauthenticated requests and rendering
76 | * responses accordingly. Routes that require authentication will need to guard
77 | * that condition.
78 | *
79 | * This function is protected, and should not be called directly. Instead,
80 | * use `passport.authenticate()` middleware and specify the {@link SessionStrategy#name `name`}
81 | * of this strategy and any options.
82 | *
83 | * @protected
84 | * @param {http.IncomingMessage} req - The Node.js {@link https://nodejs.org/api/http.html#class-httpincomingmessage `IncomingMessage`}
85 | * object.
86 | * @param {Object} [options]
87 | * @param {boolean} [options.pauseStream=false] - When `true`, data events on
88 | * the request will be paused, and then resumed after the asynchronous
89 | * `deserializeUser` function has completed. This is only necessary in
90 | * cases where later middleware in the stack are listening for events,
91 | * and ensures that those events are not missed.
92 | *
93 | * @example
94 | * passport.authenticate('session');
95 | */
96 | SessionStrategy.prototype.authenticate = function(req, options) {
97 | if (!req.session) { return this.error(new Error('Login sessions require session support. Did you forget to use `express-session` middleware?')); }
98 | options = options || {};
99 |
100 | var self = this,
101 | su;
102 | if (req.session[this._key]) {
103 | su = req.session[this._key].user;
104 | }
105 |
106 | if (su || su === 0) {
107 | // NOTE: Stream pausing is desirable in the case where later middleware is
108 | // listening for events emitted from request. For discussion on the
109 | // matter, refer to: https://github.com/jaredhanson/passport/pull/106
110 |
111 | var paused = options.pauseStream ? pause(req) : null;
112 | this._deserializeUser(su, req, function(err, user) {
113 | if (err) { return self.error(err); }
114 | if (!user) {
115 | delete req.session[self._key].user;
116 | } else {
117 | var property = req._userProperty || 'user';
118 | req[property] = user;
119 | }
120 | self.pass();
121 | if (paused) {
122 | paused.resume();
123 | }
124 | });
125 | } else {
126 | self.pass();
127 | }
128 | };
129 |
130 | // Export `SessionStrategy`.
131 | module.exports = SessionStrategy;
132 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "passport",
3 | "version": "0.7.0",
4 | "description": "Simple, unobtrusive authentication for Node.js.",
5 | "keywords": [
6 | "express",
7 | "connect",
8 | "auth",
9 | "authn",
10 | "authentication"
11 | ],
12 | "author": {
13 | "name": "Jared Hanson",
14 | "email": "jaredhanson@gmail.com",
15 | "url": "https://www.jaredhanson.me/"
16 | },
17 | "homepage": "https://www.passportjs.org/",
18 | "repository": {
19 | "type": "git",
20 | "url": "git://github.com/jaredhanson/passport.git"
21 | },
22 | "bugs": {
23 | "url": "https://github.com/jaredhanson/passport/issues"
24 | },
25 | "funding": {
26 | "type": "github",
27 | "url": "https://github.com/sponsors/jaredhanson"
28 | },
29 | "license": "MIT",
30 | "licenses": [
31 | {
32 | "type": "MIT",
33 | "url": "https://opensource.org/licenses/MIT"
34 | }
35 | ],
36 | "main": "./lib",
37 | "dependencies": {
38 | "passport-strategy": "1.x.x",
39 | "pause": "0.0.1",
40 | "utils-merge": "^1.0.1"
41 | },
42 | "devDependencies": {
43 | "make-node": "0.3.x",
44 | "mocha": "2.x.x",
45 | "chai": "2.x.x",
46 | "chai-connect-middleware": "0.3.x",
47 | "chai-passport-strategy": "0.2.x",
48 | "proxyquire": "1.4.x"
49 | },
50 | "engines": {
51 | "node": ">= 0.4.0"
52 | },
53 | "scripts": {
54 | "test": "node_modules/.bin/mocha --reporter spec --require test/bootstrap/node test/*.test.js test/**/*.test.js"
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/sponsors/auth0-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jaredhanson/passport/217018dbc46dcd4118dd6f2c60c8d97010c587f8/sponsors/auth0-dark.png
--------------------------------------------------------------------------------
/sponsors/auth0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jaredhanson/passport/217018dbc46dcd4118dd6f2c60c8d97010c587f8/sponsors/auth0.png
--------------------------------------------------------------------------------
/sponsors/descope-dark.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
13 |
14 |
15 |
16 |
17 |
18 |
20 |
21 |
22 |
23 |
24 |
25 |
28 |
29 |
30 |
31 |
35 |
40 |
45 |
49 |
54 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
78 |
79 |
80 |
--------------------------------------------------------------------------------
/sponsors/descope.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
63 |
68 |
73 |
77 |
82 |
86 |
87 |
88 |
89 |
90 |
--------------------------------------------------------------------------------
/sponsors/fusionauth.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jaredhanson/passport/217018dbc46dcd4118dd6f2c60c8d97010c587f8/sponsors/fusionauth.png
--------------------------------------------------------------------------------
/sponsors/fusionauth.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | image/svg+xml
45 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
65 |
71 |
77 |
83 |
89 |
95 |
101 |
104 |
110 |
116 |
122 |
128 |
134 |
140 |
144 |
150 |
154 |
160 |
171 |
--------------------------------------------------------------------------------
/sponsors/loginradius.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jaredhanson/passport/217018dbc46dcd4118dd6f2c60c8d97010c587f8/sponsors/loginradius.png
--------------------------------------------------------------------------------
/sponsors/snyk.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jaredhanson/passport/217018dbc46dcd4118dd6f2c60c8d97010c587f8/sponsors/snyk.png
--------------------------------------------------------------------------------
/sponsors/stytch-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jaredhanson/passport/217018dbc46dcd4118dd6f2c60c8d97010c587f8/sponsors/stytch-dark.png
--------------------------------------------------------------------------------
/sponsors/stytch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jaredhanson/passport/217018dbc46dcd4118dd6f2c60c8d97010c587f8/sponsors/stytch.png
--------------------------------------------------------------------------------
/sponsors/workos.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jaredhanson/passport/217018dbc46dcd4118dd6f2c60c8d97010c587f8/sponsors/workos.png
--------------------------------------------------------------------------------
/test/authenticator.framework.test.js:
--------------------------------------------------------------------------------
1 | /* global describe, it, expect */
2 |
3 | var Authenticator = require('../lib/authenticator');
4 |
5 |
6 | describe('Authenticator', function() {
7 |
8 | describe('#framework', function() {
9 |
10 | describe('with an authenticate function used for authorization', function() {
11 | var passport = new Authenticator();
12 | passport.framework({
13 | initialize: function() {
14 | return function() {};
15 | },
16 | authenticate: function(passport, name, options) {
17 | return function() {
18 | return 'authenticate(): ' + name + ' ' + options.assignProperty;
19 | };
20 | }
21 | });
22 |
23 | var rv = passport.authorize('foo')();
24 | it('should call authenticate', function() {
25 | expect(rv).to.equal('authenticate(): foo account');
26 | });
27 | });
28 |
29 | describe('with an authorize function used for authorization', function() {
30 | var passport = new Authenticator();
31 | passport.framework({
32 | initialize: function() {
33 | return function() {};
34 | },
35 | authenticate: function(passport, name, options) {
36 | return function() {
37 | return 'authenticate(): ' + name + ' ' + options.assignProperty;
38 | };
39 | },
40 | authorize: function(passport, name, options) {
41 | return function() {
42 | return 'authorize(): ' + name + ' ' + options.assignProperty;
43 | };
44 | }
45 | });
46 |
47 | var rv = passport.authorize('foo')();
48 | it('should call authorize', function() {
49 | expect(rv).to.equal('authorize(): foo account');
50 | });
51 | });
52 |
53 | });
54 |
55 | });
56 |
--------------------------------------------------------------------------------
/test/authenticator.middleware.test.js:
--------------------------------------------------------------------------------
1 | /* global describe, it, expect, before */
2 | /* jshint expr: true */
3 |
4 | var chai = require('chai')
5 | , Authenticator = require('../lib/authenticator');
6 |
7 |
8 | describe('Authenticator', function() {
9 |
10 | describe('#initialize', function() {
11 |
12 | it('should have correct arity', function() {
13 | var passport = new Authenticator();
14 | expect(passport.initialize).to.have.length(1);
15 | });
16 |
17 | describe('handling a request', function() {
18 | var passport = new Authenticator();
19 | var request, error;
20 |
21 | before(function(done) {
22 | chai.connect.use(passport.initialize())
23 | .req(function(req) {
24 | request = req;
25 | req.session = {};
26 | })
27 | .next(function(err) {
28 | error = err;
29 | done();
30 | })
31 | .dispatch();
32 | });
33 |
34 | it('should not error', function() {
35 | expect(error).to.be.undefined;
36 | });
37 |
38 | it('should not set user property on request', function() {
39 | expect(request._userProperty).to.be.undefined;
40 | });
41 |
42 | it('should not initialize namespace within session', function() {
43 | expect(request.session.passport).to.be.undefined;
44 | });
45 |
46 | it('should expose authenticator on internal request property', function() {
47 | expect(request._passport).to.be.an('object');
48 | expect(request._passport.instance).to.be.an.instanceOf(Authenticator);
49 | expect(request._passport.instance).to.equal(passport);
50 | expect(request._passport.instance._sm).to.be.an('object');
51 | expect(request._passport.instance._userProperty).to.equal('user');
52 | });
53 | });
54 |
55 | describe('handling a request with custom user property', function() {
56 | var passport = new Authenticator();
57 | var request, error;
58 |
59 | before(function(done) {
60 | chai.connect.use(passport.initialize({ userProperty: 'currentUser' }))
61 | .req(function(req) {
62 | request = req;
63 | req.session = {};
64 | })
65 | .next(function(err) {
66 | error = err;
67 | done();
68 | })
69 | .dispatch();
70 | });
71 |
72 | it('should not error', function() {
73 | expect(error).to.be.undefined;
74 | });
75 |
76 | it('should set user property on request', function() {
77 | expect(request._userProperty).to.equal('currentUser');
78 | });
79 |
80 | it('should not initialize namespace within session', function() {
81 | expect(request.session.passport).to.be.undefined;
82 | });
83 |
84 | it('should expose authenticator on internal request property', function() {
85 | expect(request._passport).to.be.an('object');
86 | expect(request._passport.instance).to.be.an.instanceOf(Authenticator);
87 | expect(request._passport.instance).to.equal(passport);
88 | expect(request._passport.instance._sm).to.be.an('object');
89 | expect(request._passport.instance._userProperty).to.equal('currentUser');
90 | });
91 | });
92 |
93 | });
94 |
95 |
96 | describe('#authenticate', function() {
97 |
98 | it('should have correct arity', function() {
99 | var passport = new Authenticator();
100 | expect(passport.authenticate).to.have.length(3);
101 | });
102 |
103 | describe('handling a request', function() {
104 | function Strategy() {
105 | }
106 | Strategy.prototype.authenticate = function(req) {
107 | var user = { id: '1', username: 'jaredhanson' };
108 | this.success(user);
109 | };
110 |
111 | var passport = new Authenticator();
112 | passport.use('success', new Strategy());
113 |
114 | var request, error;
115 |
116 | before(function(done) {
117 | chai.connect.use(passport.authenticate('success'))
118 | .req(function(req) {
119 | request = req;
120 |
121 | req.logIn = function(user, options, done) {
122 | this.user = user;
123 | done();
124 | };
125 | })
126 | .next(function(err) {
127 | error = err;
128 | done();
129 | })
130 | .dispatch();
131 | });
132 |
133 | it('should not error', function() {
134 | expect(error).to.be.undefined;
135 | });
136 |
137 | it('should set user', function() {
138 | expect(request.user).to.be.an('object');
139 | expect(request.user.id).to.equal('1');
140 | expect(request.user.username).to.equal('jaredhanson');
141 | });
142 |
143 | it('should set authInfo', function() {
144 | expect(request.authInfo).to.be.an('object');
145 | expect(Object.keys(request.authInfo)).to.have.length(0);
146 | });
147 | });
148 |
149 | describe('handling a request with instantiated strategy', function() {
150 | function Strategy() {
151 | }
152 | Strategy.prototype.authenticate = function(req) {
153 | var user = { id: '1', username: 'jaredhanson' };
154 | this.success(user);
155 | };
156 |
157 | var passport = new Authenticator();
158 |
159 | var request, error;
160 |
161 | before(function(done) {
162 | chai.connect.use(passport.authenticate(new Strategy()))
163 | .req(function(req) {
164 | request = req;
165 |
166 | req.logIn = function(user, options, done) {
167 | this.user = user;
168 | done();
169 | };
170 | })
171 | .next(function(err) {
172 | error = err;
173 | done();
174 | })
175 | .dispatch();
176 | });
177 |
178 | it('should not error', function() {
179 | expect(error).to.be.undefined;
180 | });
181 |
182 | it('should set user', function() {
183 | expect(request.user).to.be.an('object');
184 | expect(request.user.id).to.equal('1');
185 | expect(request.user.username).to.equal('jaredhanson');
186 | });
187 |
188 | it('should set authInfo', function() {
189 | expect(request.authInfo).to.be.an('object');
190 | expect(Object.keys(request.authInfo)).to.have.length(0);
191 | });
192 | });
193 |
194 | });
195 |
196 |
197 | describe('#authorize', function() {
198 |
199 | it('should have correct arity', function() {
200 | var passport = new Authenticator();
201 | expect(passport.authorize).to.have.length(3);
202 | });
203 |
204 | describe('handling a request', function() {
205 | function Strategy() {
206 | }
207 | Strategy.prototype.authenticate = function(req) {
208 | var user = { id: '1', username: 'jaredhanson' };
209 | this.success(user);
210 | };
211 |
212 | var passport = new Authenticator();
213 | passport.use('success', new Strategy());
214 |
215 | var request, error;
216 |
217 | before(function(done) {
218 | chai.connect.use(passport.authorize('success'))
219 | .req(function(req) {
220 | request = req;
221 |
222 | req.logIn = function(user, options, done) {
223 | this.user = user;
224 | done();
225 | };
226 | })
227 | .next(function(err) {
228 | error = err;
229 | done();
230 | })
231 | .dispatch();
232 | });
233 |
234 | it('should not error', function() {
235 | expect(error).to.be.undefined;
236 | });
237 |
238 | it('should not set user', function() {
239 | expect(request.user).to.be.undefined;
240 | });
241 |
242 | it('should set account', function() {
243 | expect(request.account).to.be.an('object');
244 | expect(request.account.id).to.equal('1');
245 | expect(request.account.username).to.equal('jaredhanson');
246 | });
247 |
248 | it('should set authInfo to empty object', function() {
249 | expect(request.authInfo).to.deep.equal({});
250 | });
251 | });
252 |
253 | describe('handling a request with authInfo disabled', function() {
254 | function Strategy() {
255 | }
256 | Strategy.prototype.authenticate = function(req) {
257 | var user = { id: '1', username: 'jaredhanson' };
258 | this.success(user);
259 | };
260 |
261 | var passport = new Authenticator();
262 | passport.use('success', new Strategy());
263 |
264 | var request, error;
265 |
266 | before(function(done) {
267 | chai.connect.use(passport.authorize('success', { authInfo: false }))
268 | .req(function(req) {
269 | request = req;
270 |
271 | req.logIn = function(user, options, done) {
272 | this.user = user;
273 | done();
274 | };
275 | })
276 | .next(function(err) {
277 | error = err;
278 | done();
279 | })
280 | .dispatch();
281 | });
282 |
283 | it('should not error', function() {
284 | expect(error).to.be.undefined;
285 | });
286 |
287 | it('should not set user', function() {
288 | expect(request.user).to.be.undefined;
289 | });
290 |
291 | it('should set account', function() {
292 | expect(request.account).to.be.an('object');
293 | expect(request.account.id).to.equal('1');
294 | expect(request.account.username).to.equal('jaredhanson');
295 | });
296 |
297 | it('should not set authInfo', function() {
298 | expect(request.authInfo).to.be.undefined;
299 | });
300 | });
301 |
302 | });
303 |
304 | describe('#session', function() {
305 |
306 | it('should have correct arity', function() {
307 | var passport = new Authenticator();
308 | expect(passport.session).to.have.length(1);
309 | });
310 |
311 | describe('handling a request', function() {
312 | var passport = new Authenticator();
313 | passport.deserializeUser(function(user, done) {
314 | done(null, { id: user });
315 | });
316 |
317 | var request, error;
318 |
319 | before(function(done) {
320 | chai.connect.use(passport.session())
321 | .req(function(req) {
322 | request = req;
323 |
324 | req._passport = {};
325 | req._passport.instance = {};
326 | req.session = {};
327 | req.session['passport'] = {};
328 | req.session['passport'].user = '123456';
329 | })
330 | .next(function(err) {
331 | error = err;
332 | done();
333 | })
334 | .dispatch();
335 | });
336 |
337 | it('should not error', function() {
338 | expect(error).to.be.undefined;
339 | });
340 |
341 | it('should set user', function() {
342 | expect(request.user).to.be.an('object');
343 | expect(request.user.id).to.equal('123456');
344 | });
345 |
346 | it('should maintain session', function() {
347 | expect(request.session['passport']).to.be.an('object');
348 | expect(request.session['passport'].user).to.equal('123456');
349 | });
350 | });
351 |
352 | });
353 |
354 | });
355 |
--------------------------------------------------------------------------------
/test/bootstrap/node.js:
--------------------------------------------------------------------------------
1 | var chai = require('chai');
2 |
3 | chai.use(require('chai-connect-middleware'));
4 | chai.use(require('chai-passport-strategy'));
5 |
6 | global.$require = require('proxyquire');
7 | global.expect = chai.expect;
8 |
--------------------------------------------------------------------------------
/test/middleware/authenticate.error.callback.test.js:
--------------------------------------------------------------------------------
1 | /* global describe, it, expect, before */
2 | /* jshint expr: true */
3 |
4 | var chai = require('chai')
5 | , authenticate = require('../../lib/middleware/authenticate')
6 | , Passport = require('../..').Passport;
7 |
8 |
9 | describe('middleware/authenticate', function() {
10 |
11 | describe('error with callback', function() {
12 | function Strategy() {
13 | }
14 | Strategy.prototype.authenticate = function(req) {
15 | this.error(new Error('something is wrong'));
16 | };
17 |
18 | var passport = new Passport();
19 | passport.use('error', new Strategy());
20 |
21 | var request, error, user;
22 |
23 | before(function(done) {
24 | function callback(e, u) {
25 | error = e;
26 | user = u;
27 | done();
28 | }
29 |
30 | chai.connect.use(authenticate(passport, 'error', callback))
31 | .req(function(req) {
32 | request = req;
33 | })
34 | .dispatch();
35 | });
36 |
37 | it('should pass error to callback', function() {
38 | expect(error).to.be.an.instanceOf(Error);
39 | expect(error.message).to.equal('something is wrong');
40 | });
41 |
42 | it('should pass user as undefined to callback', function() {
43 | expect(request.user).to.be.undefined;
44 | });
45 |
46 | it('should not set user on request', function() {
47 | expect(request.user).to.be.undefined;
48 | });
49 | });
50 |
51 | describe('error with callback and options passed to middleware', function() {
52 | function Strategy() {
53 | }
54 | Strategy.prototype.authenticate = function(req) {
55 | this.error(new Error('something is wrong'));
56 | };
57 |
58 | var passport = new Passport();
59 | passport.use('error', new Strategy());
60 |
61 | var request, error, user;
62 |
63 | before(function(done) {
64 | function callback(e, u) {
65 | error = e;
66 | user = u;
67 | done();
68 | }
69 |
70 | chai.connect.use(authenticate(passport, 'error', { foo: 'bar' }, callback))
71 | .req(function(req) {
72 | request = req;
73 | })
74 | .dispatch();
75 | });
76 |
77 | it('should pass error to callback', function() {
78 | expect(error).to.be.an.instanceOf(Error);
79 | expect(error.message).to.equal('something is wrong');
80 | });
81 |
82 | it('should pass user as undefined to callback', function() {
83 | expect(request.user).to.be.undefined;
84 | });
85 |
86 | it('should not set user on request', function() {
87 | expect(request.user).to.be.undefined;
88 | });
89 | });
90 |
91 | });
92 |
--------------------------------------------------------------------------------
/test/middleware/authenticate.error.test.js:
--------------------------------------------------------------------------------
1 | /* global describe, it, expect, before */
2 | /* jshint expr: true */
3 |
4 | var chai = require('chai')
5 | , authenticate = require('../../lib/middleware/authenticate')
6 | , Passport = require('../..').Passport;
7 |
8 |
9 | describe('middleware/authenticate', function() {
10 |
11 | describe('error', function() {
12 | function Strategy() {
13 | }
14 | Strategy.prototype.authenticate = function(req) {
15 | this.error(new Error('something is wrong'));
16 | };
17 |
18 | var passport = new Passport();
19 | passport.use('error', new Strategy());
20 |
21 | var request, error;
22 |
23 | before(function(done) {
24 | chai.connect.use(authenticate(passport, 'error'))
25 | .req(function(req) {
26 | request = req;
27 | })
28 | .next(function(err) {
29 | error = err;
30 | done();
31 | })
32 | .dispatch();
33 | });
34 |
35 | it('should error', function() {
36 | expect(error).to.be.an.instanceOf(Error);
37 | expect(error.message).to.equal('something is wrong');
38 | });
39 |
40 | it('should not set user', function() {
41 | expect(request.user).to.be.undefined;
42 | });
43 | });
44 |
45 | });
46 |
--------------------------------------------------------------------------------
/test/middleware/authenticate.fail.callback.test.js:
--------------------------------------------------------------------------------
1 | /* global describe, it, expect, before */
2 | /* jshint expr: true */
3 |
4 | var chai = require('chai')
5 | , authenticate = require('../../lib/middleware/authenticate')
6 | , Passport = require('../..').Passport;
7 |
8 |
9 | describe('middleware/authenticate', function() {
10 |
11 | describe('fail with callback', function() {
12 | function Strategy() {
13 | }
14 | Strategy.prototype.authenticate = function(req) {
15 | this.fail();
16 | };
17 |
18 | var passport = new Passport();
19 | passport.use('fail', new Strategy());
20 |
21 | var request, error, user;
22 |
23 | before(function(done) {
24 | function callback(e, u) {
25 | error = e;
26 | user = u;
27 | done();
28 | }
29 |
30 | chai.connect.use(authenticate(passport, 'fail', callback))
31 | .req(function(req) {
32 | request = req;
33 | })
34 | .dispatch();
35 | });
36 |
37 | it('should not error', function() {
38 | expect(error).to.be.null;
39 | });
40 |
41 | it('should pass false to callback', function() {
42 | expect(user).to.equal(false);
43 | });
44 |
45 | it('should not set user on request', function() {
46 | expect(request.user).to.be.undefined;
47 | });
48 | });
49 |
50 | describe('fail with callback, passing info', function() {
51 | function Strategy() {
52 | }
53 | Strategy.prototype.authenticate = function(req) {
54 | this.fail({ message: 'Invalid password' });
55 | };
56 |
57 | var passport = new Passport();
58 | passport.use('fail', new Strategy());
59 |
60 | var request, error, user, info, status;
61 |
62 | before(function(done) {
63 | function callback(e, u, i, s) {
64 | error = e;
65 | user = u;
66 | info = i;
67 | status = s;
68 | done();
69 | }
70 |
71 | chai.connect.use(authenticate(passport, 'fail', callback))
72 | .req(function(req) {
73 | request = req;
74 | })
75 | .dispatch();
76 | });
77 |
78 | it('should not error', function() {
79 | expect(error).to.be.null;
80 | });
81 |
82 | it('should pass false to callback', function() {
83 | expect(user).to.equal(false);
84 | });
85 |
86 | it('should pass info to callback', function() {
87 | expect(info).to.be.an('object');
88 | expect(info.message).to.equal('Invalid password');
89 | });
90 |
91 | it('should pass status to callback', function() {
92 | expect(status).to.be.undefined;
93 | });
94 |
95 | it('should not set user on request', function() {
96 | expect(request.user).to.be.undefined;
97 | });
98 | });
99 |
100 | describe('fail with callback, passing info and status', function() {
101 | function Strategy() {
102 | }
103 | Strategy.prototype.authenticate = function(req) {
104 | this.fail({ message: 'Invalid password' }, 403);
105 | };
106 |
107 | var passport = new Passport();
108 | passport.use('fail', new Strategy());
109 |
110 | var request, error, user, info, status;
111 |
112 | before(function(done) {
113 | function callback(e, u, i, s) {
114 | error = e;
115 | user = u;
116 | info = i;
117 | status = s;
118 | done();
119 | }
120 |
121 | chai.connect.use(authenticate(passport, 'fail', callback))
122 | .req(function(req) {
123 | request = req;
124 | })
125 | .dispatch();
126 | });
127 |
128 | it('should not error', function() {
129 | expect(error).to.be.null;
130 | });
131 |
132 | it('should pass false to callback', function() {
133 | expect(user).to.equal(false);
134 | });
135 |
136 | it('should pass info to callback', function() {
137 | expect(info).to.be.an('object');
138 | expect(info.message).to.equal('Invalid password');
139 | });
140 |
141 | it('should pass status to callback', function() {
142 | expect(status).to.equal(403);
143 | });
144 |
145 | it('should not set user on request', function() {
146 | expect(request.user).to.be.undefined;
147 | });
148 | });
149 |
150 | describe('fail with callback, passing challenge', function() {
151 | function Strategy() {
152 | }
153 | Strategy.prototype.authenticate = function(req) {
154 | this.fail('Bearer challenge');
155 | };
156 |
157 | var passport = new Passport();
158 | passport.use('fail', new Strategy());
159 |
160 | var request, error, user, challenge, status;
161 |
162 | before(function(done) {
163 | function callback(e, u, c, s) {
164 | error = e;
165 | user = u;
166 | challenge = c;
167 | status = s;
168 | done();
169 | }
170 |
171 | chai.connect.use(authenticate(passport, 'fail', callback))
172 | .req(function(req) {
173 | request = req;
174 | })
175 | .dispatch();
176 | });
177 |
178 | it('should not error', function() {
179 | expect(error).to.be.null;
180 | });
181 |
182 | it('should pass false to callback', function() {
183 | expect(user).to.equal(false);
184 | });
185 |
186 | it('should pass challenge to callback', function() {
187 | expect(challenge).to.equal('Bearer challenge');
188 | });
189 |
190 | it('should pass status to callback', function() {
191 | expect(status).to.be.undefined;
192 | });
193 |
194 | it('should not set user on request', function() {
195 | expect(request.user).to.be.undefined;
196 | });
197 | });
198 |
199 | describe('fail with callback, passing challenge and status', function() {
200 | function Strategy() {
201 | }
202 | Strategy.prototype.authenticate = function(req) {
203 | this.fail('Bearer challenge', 403);
204 | };
205 |
206 | var passport = new Passport();
207 | passport.use('fail', new Strategy());
208 |
209 | var request, error, user, challenge, status;
210 |
211 | before(function(done) {
212 | function callback(e, u, c, s) {
213 | error = e;
214 | user = u;
215 | challenge = c;
216 | status = s;
217 | done();
218 | }
219 |
220 | chai.connect.use(authenticate(passport, 'fail', callback))
221 | .req(function(req) {
222 | request = req;
223 | })
224 | .dispatch();
225 | });
226 |
227 | it('should not error', function() {
228 | expect(error).to.be.null;
229 | });
230 |
231 | it('should pass false to callback', function() {
232 | expect(user).to.equal(false);
233 | });
234 |
235 | it('should pass challenge to callback', function() {
236 | expect(challenge).to.equal('Bearer challenge');
237 | });
238 |
239 | it('should pass status to callback', function() {
240 | expect(status).to.equal(403);
241 | });
242 |
243 | it('should not set user on request', function() {
244 | expect(request.user).to.be.undefined;
245 | });
246 | });
247 |
248 | describe('fail with callback, passing status', function() {
249 | function Strategy() {
250 | }
251 | Strategy.prototype.authenticate = function(req) {
252 | this.fail(402);
253 | };
254 |
255 | var passport = new Passport();
256 | passport.use('fail', new Strategy());
257 |
258 | var request, error, user, challenge, status;
259 |
260 | before(function(done) {
261 | function callback(e, u, c, s) {
262 | error = e;
263 | user = u;
264 | challenge = c;
265 | status = s;
266 | done();
267 | }
268 |
269 | chai.connect.use(authenticate(passport, 'fail', callback))
270 | .req(function(req) {
271 | request = req;
272 | })
273 | .dispatch();
274 | });
275 |
276 | it('should not error', function() {
277 | expect(error).to.be.null;
278 | });
279 |
280 | it('should pass false to callback', function() {
281 | expect(user).to.equal(false);
282 | });
283 |
284 | it('should pass challenge to callback', function() {
285 | expect(challenge).to.be.undefined;
286 | });
287 |
288 | it('should pass status to callback', function() {
289 | expect(status).to.equal(402);
290 | });
291 |
292 | it('should not set user on request', function() {
293 | expect(request.user).to.be.undefined;
294 | });
295 | });
296 |
297 | describe('fail with callback and options passed to middleware', function() {
298 | function Strategy() {
299 | }
300 | Strategy.prototype.authenticate = function(req) {
301 | this.fail();
302 | };
303 |
304 | var passport = new Passport();
305 | passport.use('fail', new Strategy());
306 |
307 | var request, error, user;
308 |
309 | before(function(done) {
310 | function callback(e, u) {
311 | error = e;
312 | user = u;
313 | done();
314 | }
315 |
316 | chai.connect.use(authenticate(passport, 'fail', { foo: 'bar' }, callback))
317 | .req(function(req) {
318 | request = req;
319 | })
320 | .dispatch();
321 | });
322 |
323 | it('should not error', function() {
324 | expect(error).to.be.null;
325 | });
326 |
327 | it('should pass false to callback', function() {
328 | expect(user).to.equal(false);
329 | });
330 |
331 | it('should not set user on request', function() {
332 | expect(request.user).to.be.undefined;
333 | });
334 | });
335 |
336 | });
337 |
--------------------------------------------------------------------------------
/test/middleware/authenticate.fail.message.test.js:
--------------------------------------------------------------------------------
1 | /* global describe, it, expect, before */
2 | /* jshint expr: true */
3 |
4 | var chai = require('chai')
5 | , authenticate = require('../../lib/middleware/authenticate')
6 | , Passport = require('../..').Passport;
7 |
8 |
9 | describe('middleware/authenticate', function() {
10 |
11 | describe('fail with message set by route', function() {
12 | function Strategy() {
13 | }
14 | Strategy.prototype.authenticate = function(req) {
15 | this.fail({ message: 'Invalid password' });
16 | };
17 |
18 | var passport = new Passport();
19 | passport.use('fail', new Strategy());
20 |
21 | var request, response;
22 |
23 | before(function(done) {
24 | chai.connect.use('express', authenticate(passport, 'fail', { failureMessage: 'Wrong credentials',
25 | failureRedirect: 'http://www.example.com/login' }))
26 | .req(function(req) {
27 | request = req;
28 | req.session = {};
29 | })
30 | .end(function(res) {
31 | response = res;
32 | done();
33 | })
34 | .dispatch();
35 | });
36 |
37 | it('should not set user', function() {
38 | expect(request.user).to.be.undefined;
39 | });
40 |
41 | it('should add message to session', function() {
42 | expect(request.session.messages).to.have.length(1);
43 | expect(request.session.messages[0]).to.equal('Wrong credentials');
44 | });
45 |
46 | it('should redirect', function() {
47 | expect(response.statusCode).to.equal(302);
48 | expect(response.getHeader('Location')).to.equal('http://www.example.com/login');
49 | });
50 | });
51 |
52 | describe('fail with message set by route that is added to messages', function() {
53 | function Strategy() {
54 | }
55 | Strategy.prototype.authenticate = function(req) {
56 | this.fail({ message: 'Invalid password' });
57 | };
58 |
59 | var passport = new Passport();
60 | passport.use('fail', new Strategy());
61 |
62 | var request, response;
63 |
64 | before(function(done) {
65 | chai.connect.use('express', authenticate(passport, 'fail', { failureMessage: 'Wrong credentials',
66 | failureRedirect: 'http://www.example.com/login' }))
67 | .req(function(req) {
68 | request = req;
69 | req.session = {};
70 | req.session.messages = [ 'I exist!' ];
71 | })
72 | .end(function(res) {
73 | response = res;
74 | done();
75 | })
76 | .dispatch();
77 | });
78 |
79 | it('should not set user', function() {
80 | expect(request.user).to.be.undefined;
81 | });
82 |
83 | it('should add message to session', function() {
84 | expect(request.session.messages).to.have.length(2);
85 | expect(request.session.messages[0]).to.equal('I exist!');
86 | expect(request.session.messages[1]).to.equal('Wrong credentials');
87 | });
88 |
89 | it('should redirect', function() {
90 | expect(response.statusCode).to.equal(302);
91 | expect(response.getHeader('Location')).to.equal('http://www.example.com/login');
92 | });
93 | });
94 |
95 | describe('fail with message set by strategy', function() {
96 | function Strategy() {
97 | }
98 | Strategy.prototype.authenticate = function(req) {
99 | this.fail({ message: 'Invalid password' });
100 | };
101 |
102 | var passport = new Passport();
103 | passport.use('fail', new Strategy());
104 |
105 | var request, response;
106 |
107 | before(function(done) {
108 | chai.connect.use('express', authenticate(passport, 'fail', { failureMessage: true,
109 | failureRedirect: 'http://www.example.com/login' }))
110 | .req(function(req) {
111 | request = req;
112 | req.session = {};
113 | })
114 | .end(function(res) {
115 | response = res;
116 | done();
117 | })
118 | .dispatch();
119 | });
120 |
121 | it('should not set user', function() {
122 | expect(request.user).to.be.undefined;
123 | });
124 |
125 | it('should add message to session', function() {
126 | expect(request.session.messages).to.have.length(1);
127 | expect(request.session.messages[0]).to.equal('Invalid password');
128 | });
129 |
130 | it('should redirect', function() {
131 | expect(response.statusCode).to.equal(302);
132 | expect(response.getHeader('Location')).to.equal('http://www.example.com/login');
133 | });
134 | });
135 |
136 | describe('fail with message set by strategy with extra info', function() {
137 | function Strategy() {
138 | }
139 | Strategy.prototype.authenticate = function(req) {
140 | this.fail({ message: 'Invalid password', scope: 'read' });
141 | };
142 |
143 | var passport = new Passport();
144 | passport.use('fail', new Strategy());
145 |
146 | var request, response;
147 |
148 | before(function(done) {
149 | chai.connect.use('express', authenticate(passport, 'fail', { failureMessage: true,
150 | failureRedirect: 'http://www.example.com/login' }))
151 | .req(function(req) {
152 | request = req;
153 | req.session = {};
154 | })
155 | .end(function(res) {
156 | response = res;
157 | done();
158 | })
159 | .dispatch();
160 | });
161 |
162 | it('should not set user', function() {
163 | expect(request.user).to.be.undefined;
164 | });
165 |
166 | it('should add message to session', function() {
167 | expect(request.session.messages).to.have.length(1);
168 | expect(request.session.messages[0]).to.equal('Invalid password');
169 | });
170 |
171 | it('should redirect', function() {
172 | expect(response.statusCode).to.equal(302);
173 | expect(response.getHeader('Location')).to.equal('http://www.example.com/login');
174 | });
175 | });
176 |
177 | });
178 |
--------------------------------------------------------------------------------
/test/middleware/authenticate.fail.multi.test.js:
--------------------------------------------------------------------------------
1 | /* global describe, it, expect, before */
2 | /* jshint expr: true */
3 |
4 | var chai = require('chai')
5 | , authenticate = require('../../lib/middleware/authenticate')
6 | , Passport = require('../..').Passport;
7 |
8 |
9 | describe('middleware/authenticate', function() {
10 |
11 | describe('with multiple strategies, all of which fail, and responding with unauthorized status', function() {
12 | function BasicStrategy() {
13 | }
14 | BasicStrategy.prototype.authenticate = function(req) {
15 | this.fail('BASIC challenge');
16 | };
17 |
18 | function DigestStrategy() {
19 | }
20 | DigestStrategy.prototype.authenticate = function(req) {
21 | this.fail('DIGEST challenge');
22 | };
23 |
24 | function NoChallengeStrategy() {
25 | }
26 | NoChallengeStrategy.prototype.authenticate = function(req) {
27 | this.fail();
28 | };
29 |
30 | var passport = new Passport();
31 | passport.use('basic', new BasicStrategy());
32 | passport.use('digest', new DigestStrategy());
33 | passport.use('no-challenge', new NoChallengeStrategy());
34 |
35 | var request, response;
36 |
37 | before(function(done) {
38 | chai.connect.use(authenticate(passport, ['basic', 'no-challenge', 'digest']))
39 | .req(function(req) {
40 | request = req;
41 |
42 | req.flash = function(type, msg) {
43 | this.message = { type: type, msg: msg };
44 | };
45 | })
46 | .end(function(res) {
47 | response = res;
48 | done();
49 | })
50 | .dispatch();
51 | });
52 |
53 | it('should not set user', function() {
54 | expect(request.user).to.be.undefined;
55 | });
56 |
57 | it('should respond', function() {
58 | expect(response.statusCode).to.equal(401);
59 | expect(response.body).to.equal('Unauthorized');
60 | });
61 |
62 | it('should set authenticate header on response', function() {
63 | var val = response.getHeader('WWW-Authenticate');
64 | expect(val).to.be.an('array');
65 | expect(val).to.have.length(2);
66 |
67 | expect(val[0]).to.equal('BASIC challenge');
68 | expect(val[1]).to.equal('DIGEST challenge');
69 | });
70 | });
71 |
72 | describe('with multiple strategies, all of which fail, and responding with specified status', function() {
73 | function BasicStrategy() {
74 | }
75 | BasicStrategy.prototype.authenticate = function(req) {
76 | this.fail('BASIC challenge', 400);
77 | };
78 |
79 | function BearerStrategy() {
80 | }
81 | BearerStrategy.prototype.authenticate = function(req) {
82 | this.fail('BEARER challenge', 403);
83 | };
84 |
85 | function NoChallengeStrategy() {
86 | }
87 | NoChallengeStrategy.prototype.authenticate = function(req) {
88 | this.fail(402);
89 | };
90 |
91 | var passport = new Passport();
92 | passport.use('basic', new BasicStrategy());
93 | passport.use('bearer', new BearerStrategy());
94 | passport.use('no-challenge', new NoChallengeStrategy());
95 |
96 | var request, response;
97 |
98 | before(function(done) {
99 | chai.connect.use(authenticate(passport, ['basic', 'no-challenge', 'bearer']))
100 | .req(function(req) {
101 | request = req;
102 |
103 | req.flash = function(type, msg) {
104 | this.message = { type: type, msg: msg };
105 | };
106 | })
107 | .end(function(res) {
108 | response = res;
109 | done();
110 | })
111 | .dispatch();
112 | });
113 |
114 | it('should not set user', function() {
115 | expect(request.user).to.be.undefined;
116 | });
117 |
118 | it('should respond', function() {
119 | expect(response.statusCode).to.equal(400);
120 | expect(response.getHeader('WWW-Authenticate')).to.be.undefined;
121 | expect(response.body).to.equal('Bad Request');
122 | });
123 | });
124 |
125 | describe('with multiple strategies, all of which fail, and flashing message', function() {
126 | function StrategyA() {
127 | }
128 | StrategyA.prototype.authenticate = function(req) {
129 | this.fail('A message');
130 | };
131 |
132 | function StrategyB() {
133 | }
134 | StrategyB.prototype.authenticate = function(req) {
135 | this.fail('B message');
136 | };
137 |
138 | var passport = new Passport();
139 | passport.use('a', new StrategyA());
140 | passport.use('b', new StrategyB());
141 |
142 | var request, response;
143 |
144 | before(function(done) {
145 | chai.connect.use('express', authenticate(passport, ['a', 'b'], { failureFlash: true,
146 | failureRedirect: 'http://www.example.com/login' }))
147 | .req(function(req) {
148 | request = req;
149 |
150 | req.flash = function(type, msg) {
151 | this.message = { type: type, msg: msg };
152 | };
153 | })
154 | .end(function(res) {
155 | response = res;
156 | done();
157 | })
158 | .dispatch();
159 | });
160 |
161 | it('should not set user', function() {
162 | expect(request.user).to.be.undefined;
163 | });
164 |
165 | it('should flash message', function() {
166 | expect(request.message.type).to.equal('error');
167 | expect(request.message.msg).to.equal('A message');
168 | });
169 |
170 | it('should redirect', function() {
171 | expect(response.statusCode).to.equal(302);
172 | expect(response.getHeader('Location')).to.equal('http://www.example.com/login');
173 | });
174 | });
175 |
176 | describe('with multiple strategies, all of which fail with unauthorized status, and invoking callback', function() {
177 | function BasicStrategy() {
178 | }
179 | BasicStrategy.prototype.authenticate = function(req) {
180 | this.fail('BASIC challenge');
181 | };
182 |
183 | function DigestStrategy() {
184 | }
185 | DigestStrategy.prototype.authenticate = function(req) {
186 | this.fail('DIGEST challenge');
187 | };
188 |
189 | function NoChallengeStrategy() {
190 | }
191 | NoChallengeStrategy.prototype.authenticate = function(req) {
192 | this.fail();
193 | };
194 |
195 | var passport = new Passport();
196 | passport.use('basic', new BasicStrategy());
197 | passport.use('digest', new DigestStrategy());
198 | passport.use('no-challenge', new NoChallengeStrategy());
199 |
200 | var request, error, user, challenge, status;
201 |
202 | before(function(done) {
203 | function callback(e, u, c, s) {
204 | error = e;
205 | user = u;
206 | challenge = c;
207 | status = s;
208 | done();
209 | }
210 |
211 | chai.connect.use(authenticate(passport, ['basic', 'no-challenge', 'digest'], callback))
212 | .req(function(req) {
213 | request = req;
214 | })
215 | .dispatch();
216 | });
217 |
218 | it('should not error', function() {
219 | expect(error).to.be.null;
220 | });
221 |
222 | it('should pass false to callback', function() {
223 | expect(user).to.equal(false);
224 | });
225 |
226 | it('should pass challenges to callback', function() {
227 | expect(challenge).to.be.an('array');
228 | expect(challenge).to.have.length(3);
229 | expect(challenge[0]).to.equal('BASIC challenge');
230 | expect(challenge[1]).to.be.undefined;
231 | expect(challenge[2]).to.equal('DIGEST challenge');
232 | });
233 |
234 | it('should pass statuses to callback', function() {
235 | expect(status).to.be.an('array');
236 | expect(status).to.have.length(3);
237 | expect(status[0]).to.be.undefined;
238 | expect(status[1]).to.be.undefined;
239 | expect(status[2]).to.be.undefined;
240 | });
241 |
242 | it('should not set user on request', function() {
243 | expect(request.user).to.be.undefined;
244 | });
245 | });
246 |
247 | describe('with multiple strategies, all of which fail with specific status, and invoking callback', function() {
248 | function BasicStrategy() {
249 | }
250 | BasicStrategy.prototype.authenticate = function(req) {
251 | this.fail('BASIC challenge', 400);
252 | };
253 |
254 | function BearerStrategy() {
255 | }
256 | BearerStrategy.prototype.authenticate = function(req) {
257 | this.fail('BEARER challenge', 403);
258 | };
259 |
260 | function NoChallengeStrategy() {
261 | }
262 | NoChallengeStrategy.prototype.authenticate = function(req) {
263 | this.fail(402);
264 | };
265 |
266 | var passport = new Passport();
267 | passport.use('basic', new BasicStrategy());
268 | passport.use('bearer', new BearerStrategy());
269 | passport.use('no-challenge', new NoChallengeStrategy());
270 |
271 | var request, error, user, challenge, status;
272 |
273 | before(function(done) {
274 | function callback(e, u, c, s) {
275 | error = e;
276 | user = u;
277 | challenge = c;
278 | status = s;
279 | done();
280 | }
281 |
282 | chai.connect.use(authenticate(passport, ['basic', 'no-challenge', 'bearer'], callback))
283 | .req(function(req) {
284 | request = req;
285 | })
286 | .dispatch();
287 | });
288 |
289 | it('should not error', function() {
290 | expect(error).to.be.null;
291 | });
292 |
293 | it('should pass false to callback', function() {
294 | expect(user).to.equal(false);
295 | });
296 |
297 | it('should pass challenges to callback', function() {
298 | expect(challenge).to.be.an('array');
299 | expect(challenge).to.have.length(3);
300 | expect(challenge[0]).to.equal('BASIC challenge');
301 | expect(challenge[1]).to.be.undefined;
302 | expect(challenge[2]).to.equal('BEARER challenge');
303 | });
304 |
305 | it('should pass statuses to callback', function() {
306 | expect(status).to.be.an('array');
307 | expect(status).to.have.length(3);
308 | expect(status[0]).to.equal(400);
309 | expect(status[1]).to.equal(402);
310 | expect(status[2]).to.equal(403);
311 | });
312 |
313 | it('should not set user on request', function() {
314 | expect(request.user).to.be.undefined;
315 | });
316 | });
317 |
318 | describe('with single strategy in list, which fails with unauthorized status, and invoking callback', function() {
319 | function BasicStrategy() {
320 | }
321 | BasicStrategy.prototype.authenticate = function(req) {
322 | this.fail('BASIC challenge');
323 | };
324 |
325 | var passport = new Passport();
326 | passport.use('basic', new BasicStrategy());
327 |
328 | var request, error, user, challenge, status;
329 |
330 | before(function(done) {
331 | function callback(e, u, c, s) {
332 | error = e;
333 | user = u;
334 | challenge = c;
335 | status = s;
336 | done();
337 | }
338 |
339 | chai.connect.use(authenticate(passport, ['basic'], callback))
340 | .req(function(req) {
341 | request = req;
342 | })
343 | .dispatch();
344 | });
345 |
346 | it('should not error', function() {
347 | expect(error).to.be.null;
348 | });
349 |
350 | it('should pass false to callback', function() {
351 | expect(user).to.equal(false);
352 | });
353 |
354 | it('should pass challenges to callback', function() {
355 | expect(challenge).to.be.an('array');
356 | expect(challenge).to.have.length(1);
357 | expect(challenge[0]).to.equal('BASIC challenge');
358 | });
359 |
360 | it('should pass statuses to callback', function() {
361 | expect(status).to.be.an('array');
362 | expect(status).to.have.length(1);
363 | expect(status[0]).to.be.undefined;
364 | });
365 |
366 | it('should not set user on request', function() {
367 | expect(request.user).to.be.undefined;
368 | });
369 | });
370 |
371 | });
372 |
--------------------------------------------------------------------------------
/test/middleware/authenticate.fail.test.js:
--------------------------------------------------------------------------------
1 | /* global describe, it, expect, before */
2 | /* jshint expr: true */
3 |
4 | var chai = require('chai')
5 | , authenticate = require('../../lib/middleware/authenticate')
6 | , Passport = require('../..').Passport;
7 |
8 |
9 | describe('middleware/authenticate', function() {
10 |
11 | describe('fail', function() {
12 | function Strategy() {
13 | }
14 | Strategy.prototype.authenticate = function(req) {
15 | this.fail();
16 | };
17 |
18 | var passport = new Passport();
19 | passport.use('fail', new Strategy());
20 |
21 | var request, response;
22 |
23 | before(function(done) {
24 | chai.connect.use(authenticate(passport, 'fail'))
25 | .req(function(req) {
26 | request = req;
27 | })
28 | .end(function(res) {
29 | response = res;
30 | done();
31 | })
32 | .dispatch();
33 | });
34 |
35 | it('should not set user', function() {
36 | expect(request.user).to.be.undefined;
37 | });
38 |
39 | it('should respond', function() {
40 | expect(response.statusCode).to.equal(401);
41 | expect(response.getHeader('WWW-Authenticate')).to.be.undefined;
42 | expect(response.body).to.equal('Unauthorized');
43 | });
44 | });
45 |
46 | describe('fail with redirect', function() {
47 | function Strategy() {
48 | }
49 | Strategy.prototype.authenticate = function(req) {
50 | this.fail();
51 | };
52 |
53 | var passport = new Passport();
54 | passport.use('fail', new Strategy());
55 |
56 | var request, response;
57 |
58 | before(function(done) {
59 | chai.connect.use('express', authenticate(passport, 'fail', { failureRedirect: 'http://www.example.com/login' }))
60 | .req(function(req) {
61 | request = req;
62 | })
63 | .end(function(res) {
64 | response = res;
65 | done();
66 | })
67 | .dispatch();
68 | });
69 |
70 | it('should not set user', function() {
71 | expect(request.user).to.be.undefined;
72 | });
73 |
74 | it('should redirect', function() {
75 | expect(response.statusCode).to.equal(302);
76 | expect(response.getHeader('Location')).to.equal('http://www.example.com/login');
77 | });
78 | });
79 |
80 | describe('fail with challenge', function() {
81 | function Strategy() {
82 | }
83 | Strategy.prototype.authenticate = function(req) {
84 | this.fail('MOCK challenge');
85 | };
86 |
87 | var passport = new Passport();
88 | passport.use('fail', new Strategy());
89 |
90 | var request, response;
91 |
92 | before(function(done) {
93 | chai.connect.use(authenticate(passport, 'fail'))
94 | .req(function(req) {
95 | request = req;
96 | })
97 | .end(function(res) {
98 | response = res;
99 | done();
100 | })
101 | .dispatch();
102 | });
103 |
104 | it('should not set user', function() {
105 | expect(request.user).to.be.undefined;
106 | });
107 |
108 | it('should respond', function() {
109 | expect(response.statusCode).to.equal(401);
110 | expect(response.body).to.equal('Unauthorized');
111 | });
112 |
113 | it('should set authenticate header on response', function() {
114 | var val = response.getHeader('WWW-Authenticate');
115 | expect(val).to.be.an('array');
116 | expect(val).to.have.length(1);
117 |
118 | expect(val[0]).to.equal('MOCK challenge');
119 | });
120 | });
121 |
122 | describe('fail with challenge and status', function() {
123 | function Strategy() {
124 | }
125 | Strategy.prototype.authenticate = function(req) {
126 | this.fail('MOCK challenge', 403);
127 | };
128 |
129 | var passport = new Passport();
130 | passport.use('fail', new Strategy());
131 |
132 | var request, response;
133 |
134 | before(function(done) {
135 | chai.connect.use(authenticate(passport, 'fail'))
136 | .req(function(req) {
137 | request = req;
138 | })
139 | .end(function(res) {
140 | response = res;
141 | done();
142 | })
143 | .dispatch();
144 | });
145 |
146 | it('should not set user', function() {
147 | expect(request.user).to.be.undefined;
148 | });
149 |
150 | it('should respond', function() {
151 | expect(response.statusCode).to.equal(403);
152 | expect(response.getHeader('WWW-Authenticate')).to.be.undefined;
153 | expect(response.body).to.equal('Forbidden');
154 | });
155 | });
156 |
157 | describe('fail with status', function() {
158 | function Strategy() {
159 | }
160 | Strategy.prototype.authenticate = function(req) {
161 | this.fail(400);
162 | };
163 |
164 | var passport = new Passport();
165 | passport.use('fail', new Strategy());
166 |
167 | var request, response;
168 |
169 | before(function(done) {
170 | chai.connect.use(authenticate(passport, 'fail'))
171 | .req(function(req) {
172 | request = req;
173 | })
174 | .end(function(res) {
175 | response = res;
176 | done();
177 | })
178 | .dispatch();
179 | });
180 |
181 | it('should not set user', function() {
182 | expect(request.user).to.be.undefined;
183 | });
184 |
185 | it('should respond', function() {
186 | expect(response.statusCode).to.equal(400);
187 | expect(response.getHeader('WWW-Authenticate')).to.be.undefined;
188 | expect(response.body).to.equal('Bad Request');
189 | });
190 | });
191 |
192 | describe('fail with error', function() {
193 | function Strategy() {
194 | }
195 | Strategy.prototype.authenticate = function(req) {
196 | this.fail();
197 | };
198 |
199 | var passport = new Passport();
200 | passport.use('fail', new Strategy());
201 |
202 | var request, response, error;
203 |
204 | before(function(done) {
205 | chai.connect.use('express', authenticate(passport, 'fail', { failWithError: true }))
206 | .req(function(req) {
207 | request = req;
208 | })
209 | .res(function(res) {
210 | response = res;
211 | })
212 | .next(function(err) {
213 | error = err;
214 | done();
215 | })
216 | .dispatch();
217 | });
218 |
219 | it('should error', function() {
220 | expect(error).to.be.an.instanceOf(Error);
221 | expect(error.constructor.name).to.equal('AuthenticationError');
222 | expect(error.message).to.equal('Unauthorized');
223 | expect(error.status).to.equal(401);
224 | });
225 |
226 | it('should not set user', function() {
227 | expect(request.user).to.be.undefined;
228 | });
229 |
230 | it('should not set body of response', function() {
231 | expect(response.statusCode).to.equal(401);
232 | expect(response.getHeader('WWW-Authenticate')).to.be.undefined;
233 | expect(response.body).to.be.undefined;
234 | });
235 | });
236 |
237 | describe('fail with error, passing info to fail', function() {
238 | function Strategy() {
239 | }
240 | Strategy.prototype.authenticate = function(req) {
241 | this.fail({ message: 'Invalid credentials' });
242 | };
243 |
244 | var passport = new Passport();
245 | passport.use('fail', new Strategy());
246 |
247 | var request, response, error;
248 |
249 | before(function(done) {
250 | chai.connect.use('express', authenticate(passport, 'fail', { failWithError: true }))
251 | .req(function(req) {
252 | request = req;
253 | })
254 | .res(function(res) {
255 | response = res;
256 | })
257 | .next(function(err) {
258 | error = err;
259 | done();
260 | })
261 | .dispatch();
262 | });
263 |
264 | it('should error', function() {
265 | expect(error).to.be.an.instanceOf(Error);
266 | expect(error.constructor.name).to.equal('AuthenticationError');
267 | expect(error.message).to.equal('Unauthorized');
268 | expect(error.status).to.equal(401);
269 | });
270 |
271 | it('should not set user', function() {
272 | expect(request.user).to.be.undefined;
273 | });
274 |
275 | it('should not set body of response', function() {
276 | expect(response.statusCode).to.equal(401);
277 | expect(response.getHeader('WWW-Authenticate')).to.be.undefined;
278 | expect(response.body).to.be.undefined;
279 | });
280 | });
281 |
282 | describe('fail with error, passing info and status to fail', function() {
283 | function Strategy() {
284 | }
285 | Strategy.prototype.authenticate = function(req) {
286 | this.fail({ message: 'Multiple credentials' }, 400);
287 | };
288 |
289 | var passport = new Passport();
290 | passport.use('fail', new Strategy());
291 |
292 | var request, response, error;
293 |
294 | before(function(done) {
295 | chai.connect.use('express', authenticate(passport, 'fail', { failWithError: true }))
296 | .req(function(req) {
297 | request = req;
298 | })
299 | .res(function(res) {
300 | response = res;
301 | })
302 | .next(function(err) {
303 | error = err;
304 | done();
305 | })
306 | .dispatch();
307 | });
308 |
309 | it('should error', function() {
310 | expect(error).to.be.an.instanceOf(Error);
311 | expect(error.constructor.name).to.equal('AuthenticationError');
312 | expect(error.message).to.equal('Bad Request');
313 | expect(error.status).to.equal(400);
314 | });
315 |
316 | it('should not set user', function() {
317 | expect(request.user).to.be.undefined;
318 | });
319 |
320 | it('should not set body of response', function() {
321 | expect(response.statusCode).to.equal(400);
322 | expect(response.getHeader('WWW-Authenticate')).to.be.undefined;
323 | expect(response.body).to.be.undefined;
324 | });
325 | });
326 |
327 | describe('fail with error, passing challenge to fail', function() {
328 | function Strategy() {
329 | }
330 | Strategy.prototype.authenticate = function(req) {
331 | this.fail('Bearer challenge');
332 | };
333 |
334 | var passport = new Passport();
335 | passport.use('fail', new Strategy());
336 |
337 | var request, response, error;
338 |
339 | before(function(done) {
340 | chai.connect.use('express', authenticate(passport, 'fail', { failWithError: true }))
341 | .req(function(req) {
342 | request = req;
343 | })
344 | .res(function(res) {
345 | response = res;
346 | })
347 | .next(function(err) {
348 | error = err;
349 | done();
350 | })
351 | .dispatch();
352 | });
353 |
354 | it('should error', function() {
355 | expect(error).to.be.an.instanceOf(Error);
356 | expect(error.constructor.name).to.equal('AuthenticationError');
357 | expect(error.message).to.equal('Unauthorized');
358 | expect(error.status).to.equal(401);
359 | });
360 |
361 | it('should not set user', function() {
362 | expect(request.user).to.be.undefined;
363 | });
364 |
365 | it('should not set body of response', function() {
366 | expect(response.statusCode).to.equal(401);
367 | expect(response.body).to.be.undefined;
368 | });
369 |
370 | it('should set authenticate header on response', function() {
371 | var val = response.getHeader('WWW-Authenticate');
372 | expect(val).to.be.an('array');
373 | expect(val).to.have.length(1);
374 |
375 | expect(val[0]).to.equal('Bearer challenge');
376 | });
377 | });
378 |
379 | describe('fail with error, passing challenge and status to fail', function() {
380 | function Strategy() {
381 | }
382 | Strategy.prototype.authenticate = function(req) {
383 | this.fail('Bearer challenge', 403);
384 | };
385 |
386 | var passport = new Passport();
387 | passport.use('fail', new Strategy());
388 |
389 | var request, response, error;
390 |
391 | before(function(done) {
392 | chai.connect.use('express', authenticate(passport, 'fail', { failWithError: true }))
393 | .req(function(req) {
394 | request = req;
395 | })
396 | .res(function(res) {
397 | response = res;
398 | })
399 | .next(function(err) {
400 | error = err;
401 | done();
402 | })
403 | .dispatch();
404 | });
405 |
406 | it('should error', function() {
407 | expect(error).to.be.an.instanceOf(Error);
408 | expect(error.constructor.name).to.equal('AuthenticationError');
409 | expect(error.message).to.equal('Forbidden');
410 | expect(error.status).to.equal(403);
411 | });
412 |
413 | it('should not set user', function() {
414 | expect(request.user).to.be.undefined;
415 | });
416 |
417 | it('should not set body of response', function() {
418 | expect(response.statusCode).to.equal(403);
419 | expect(response.getHeader('WWW-Authenticate')).to.be.undefined;
420 | expect(response.body).to.be.undefined;
421 | });
422 | });
423 |
424 | describe('fail with error, passing status to fail', function() {
425 | function Strategy() {
426 | }
427 | Strategy.prototype.authenticate = function(req) {
428 | this.fail(402);
429 | };
430 |
431 | var passport = new Passport();
432 | passport.use('fail', new Strategy());
433 |
434 | var request, response, error;
435 |
436 | before(function(done) {
437 | chai.connect.use('express', authenticate(passport, 'fail', { failWithError: true }))
438 | .req(function(req) {
439 | request = req;
440 | })
441 | .res(function(res) {
442 | response = res;
443 | })
444 | .next(function(err) {
445 | error = err;
446 | done();
447 | })
448 | .dispatch();
449 | });
450 |
451 | it('should error', function() {
452 | expect(error).to.be.an.instanceOf(Error);
453 | expect(error.constructor.name).to.equal('AuthenticationError');
454 | expect(error.message).to.equal('Payment Required');
455 | expect(error.status).to.equal(402);
456 | });
457 |
458 | it('should not set user', function() {
459 | expect(request.user).to.be.undefined;
460 | });
461 |
462 | it('should not set body of response', function() {
463 | expect(response.statusCode).to.equal(402);
464 | expect(response.getHeader('WWW-Authenticate')).to.be.undefined;
465 | expect(response.body).to.be.undefined;
466 | });
467 | });
468 |
469 | });
470 |
--------------------------------------------------------------------------------
/test/middleware/authenticate.pass.test.js:
--------------------------------------------------------------------------------
1 | /* global describe, it, expect, before */
2 | /* jshint expr: true */
3 |
4 | var chai = require('chai')
5 | , authenticate = require('../../lib/middleware/authenticate')
6 | , Passport = require('../..').Passport;
7 |
8 |
9 | describe('middleware/authenticate', function() {
10 |
11 | describe('pass', function() {
12 | function Strategy() {
13 | }
14 | Strategy.prototype.authenticate = function(req) {
15 | this.pass();
16 | };
17 |
18 | var passport = new Passport();
19 | passport.use('pass', new Strategy());
20 |
21 | var request, error;
22 |
23 | before(function(done) {
24 | chai.connect.use(authenticate(passport, 'pass'))
25 | .req(function(req) {
26 | request = req;
27 | })
28 | .next(function(err) {
29 | error = err;
30 | done();
31 | })
32 | .dispatch();
33 | });
34 |
35 | it('should not error', function() {
36 | expect(error).to.be.undefined;
37 | });
38 |
39 | it('should not set user', function() {
40 | expect(request.user).to.be.undefined;
41 | });
42 | });
43 |
44 | });
45 |
--------------------------------------------------------------------------------
/test/middleware/authenticate.redirect.test.js:
--------------------------------------------------------------------------------
1 | /* global describe, it, expect, before */
2 | /* jshint expr: true */
3 |
4 | var chai = require('chai')
5 | , authenticate = require('../../lib/middleware/authenticate')
6 | , Passport = require('../..').Passport;
7 |
8 |
9 | describe('middleware/authenticate', function() {
10 |
11 | describe('redirect', function() {
12 | function Strategy() {
13 | }
14 | Strategy.prototype.authenticate = function(req) {
15 | this.redirect('http://www.example.com/idp');
16 | };
17 |
18 | var passport = new Passport();
19 | passport.use('redirect', new Strategy());
20 |
21 | var request, response;
22 |
23 | before(function(done) {
24 | chai.connect.use(authenticate(passport, 'redirect'))
25 | .req(function(req) {
26 | request = req;
27 | })
28 | .end(function(res) {
29 | response = res;
30 | done();
31 | })
32 | .dispatch();
33 | });
34 |
35 | it('should not set user', function() {
36 | expect(request.user).to.be.undefined;
37 | });
38 |
39 | it('should redirect', function() {
40 | expect(response.statusCode).to.equal(302);
41 | expect(response.getHeader('Location')).to.equal('http://www.example.com/idp');
42 | expect(response.getHeader('Content-Length')).to.equal('0');
43 | });
44 | });
45 |
46 | describe('redirect with status', function() {
47 | function Strategy() {
48 | }
49 | Strategy.prototype.authenticate = function(req) {
50 | this.redirect('http://www.example.com/idp', 303);
51 | };
52 |
53 | var passport = new Passport();
54 | passport.use('redirect', new Strategy());
55 |
56 | var request, response;
57 |
58 | before(function(done) {
59 | chai.connect.use(authenticate(passport, 'redirect'))
60 | .req(function(req) {
61 | request = req;
62 | })
63 | .end(function(res) {
64 | response = res;
65 | done();
66 | })
67 | .dispatch();
68 | });
69 |
70 | it('should not set user', function() {
71 | expect(request.user).to.be.undefined;
72 | });
73 |
74 | it('should redirect', function() {
75 | expect(response.statusCode).to.equal(303);
76 | expect(response.getHeader('Location')).to.equal('http://www.example.com/idp');
77 | expect(response.getHeader('Content-Length')).to.equal('0');
78 | });
79 | });
80 |
81 | describe('redirect using framework function', function() {
82 | function Strategy() {
83 | }
84 | Strategy.prototype.authenticate = function(req) {
85 | this.redirect('http://www.example.com/idp');
86 | };
87 |
88 | var passport = new Passport();
89 | passport.use('redirect', new Strategy());
90 |
91 | var request, response;
92 |
93 | before(function(done) {
94 | chai.connect.use('express', authenticate(passport, 'redirect'))
95 | .req(function(req) {
96 | request = req;
97 | })
98 | .end(function(res) {
99 | response = res;
100 | done();
101 | })
102 | .dispatch();
103 | });
104 |
105 | it('should not set user', function() {
106 | expect(request.user).to.be.undefined;
107 | });
108 |
109 | it('should redirect', function() {
110 | expect(response.statusCode).to.equal(302);
111 | expect(response.getHeader('Location')).to.equal('http://www.example.com/idp');
112 | });
113 | });
114 |
115 | describe('redirect with status using framework function', function() {
116 | function Strategy() {
117 | }
118 | Strategy.prototype.authenticate = function(req) {
119 | this.redirect('http://www.example.com/idp', 303);
120 | };
121 |
122 | var passport = new Passport();
123 | passport.use('redirect', new Strategy());
124 |
125 | var request, response;
126 |
127 | before(function(done) {
128 | chai.connect.use('express', authenticate(passport, 'redirect'))
129 | .req(function(req) {
130 | request = req;
131 | })
132 | .end(function(res) {
133 | response = res;
134 | done();
135 | })
136 | .dispatch();
137 | });
138 |
139 | it('should not set user', function() {
140 | expect(request.user).to.be.undefined;
141 | });
142 |
143 | it('should redirect', function() {
144 | expect(response.statusCode).to.equal(303);
145 | expect(response.getHeader('Location')).to.equal('http://www.example.com/idp');
146 | });
147 | });
148 |
149 | });
150 |
--------------------------------------------------------------------------------
/test/middleware/authenticate.success.callback.test.js:
--------------------------------------------------------------------------------
1 | /* global describe, it, expect, before */
2 | /* jshint expr: true */
3 |
4 | var chai = require('chai')
5 | , authenticate = require('../../lib/middleware/authenticate')
6 | , Passport = require('../..').Passport;
7 |
8 |
9 | describe('middleware/authenticate', function() {
10 |
11 | describe('success with callback', function() {
12 | function Strategy() {
13 | }
14 | Strategy.prototype.authenticate = function(req) {
15 | var user = { id: '1', username: 'jaredhanson' };
16 | this.success(user, { message: 'Hello' });
17 | };
18 |
19 | var passport = new Passport();
20 | passport.use('success', new Strategy());
21 |
22 | var request, error, user, info;
23 |
24 | before(function(done) {
25 | function callback(e, u, i) {
26 | error = e;
27 | user = u;
28 | info = i;
29 | done();
30 | }
31 |
32 | chai.connect.use(authenticate(passport, 'success', callback))
33 | .req(function(req) {
34 | request = req;
35 | })
36 | .dispatch();
37 | });
38 |
39 | it('should not error', function() {
40 | expect(error).to.be.null;
41 | });
42 |
43 | it('should pass user to callback', function() {
44 | expect(user).to.be.an('object');
45 | expect(user.id).to.equal('1');
46 | expect(user.username).to.equal('jaredhanson');
47 | });
48 |
49 | it('should pass info to callback', function() {
50 | expect(info).to.be.an('object');
51 | expect(info.message).to.equal('Hello');
52 | });
53 |
54 | it('should not set user on request', function() {
55 | expect(request.user).to.be.undefined;
56 | });
57 |
58 | it('should not set authInfo on request', function() {
59 | expect(request.authInfo).to.be.undefined;
60 | });
61 | });
62 |
63 | describe('success with callback and options passed to middleware', function() {
64 | function Strategy() {
65 | }
66 | Strategy.prototype.authenticate = function(req) {
67 | var user = { id: '1', username: 'jaredhanson' };
68 | this.success(user, { message: 'Hello' });
69 | };
70 |
71 | var passport = new Passport();
72 | passport.use('success', new Strategy());
73 |
74 | var request, error, user, info;
75 |
76 | before(function(done) {
77 | function callback(e, u, i) {
78 | error = e;
79 | user = u;
80 | info = i;
81 | done();
82 | }
83 |
84 | chai.connect.use(authenticate(passport, 'success', { foo: 'bar' }, callback))
85 | .req(function(req) {
86 | request = req;
87 | })
88 | .dispatch();
89 | });
90 |
91 | it('should not error', function() {
92 | expect(error).to.be.null;
93 | });
94 |
95 | it('should pass user to callback', function() {
96 | expect(user).to.be.an('object');
97 | expect(user.id).to.equal('1');
98 | expect(user.username).to.equal('jaredhanson');
99 | });
100 |
101 | it('should pass info to callback', function() {
102 | expect(info).to.be.an('object');
103 | expect(info.message).to.equal('Hello');
104 | });
105 |
106 | it('should not set user on request', function() {
107 | expect(request.user).to.be.undefined;
108 | });
109 |
110 | it('should not set authInfo on request', function() {
111 | expect(request.authInfo).to.be.undefined;
112 | });
113 | });
114 |
115 | });
116 |
--------------------------------------------------------------------------------
/test/middleware/authenticate.success.info.test.js:
--------------------------------------------------------------------------------
1 | /* global describe, it, expect, before */
2 | /* jshint expr: true */
3 |
4 | var chai = require('chai')
5 | , authenticate = require('../../lib/middleware/authenticate')
6 | , Passport = require('../..').Passport;
7 |
8 |
9 | describe('middleware/authenticate', function() {
10 |
11 | describe('success with info', function() {
12 | function Strategy() {
13 | }
14 | Strategy.prototype.authenticate = function(req) {
15 | var user = { id: '1', username: 'jaredhanson' };
16 | this.success(user, { clientId: '123', scope: 'read' });
17 | };
18 |
19 | var passport = new Passport();
20 | passport.use('success', new Strategy());
21 |
22 | var request, error;
23 |
24 | before(function(done) {
25 | chai.connect.use(authenticate(passport, 'success'))
26 | .req(function(req) {
27 | request = req;
28 |
29 | req.logIn = function(user, options, done) {
30 | this.user = user;
31 | done();
32 | };
33 | })
34 | .next(function(err) {
35 | error = err;
36 | done();
37 | })
38 | .dispatch();
39 | });
40 |
41 | it('should not error', function() {
42 | expect(error).to.be.undefined;
43 | });
44 |
45 | it('should set user', function() {
46 | expect(request.user).to.be.an('object');
47 | expect(request.user.id).to.equal('1');
48 | expect(request.user.username).to.equal('jaredhanson');
49 | });
50 |
51 | it('should set authInfo', function() {
52 | expect(request.authInfo).to.be.an('object');
53 | expect(Object.keys(request.authInfo)).to.have.length(2);
54 | expect(request.authInfo.clientId).to.equal('123');
55 | expect(request.authInfo.scope).to.equal('read');
56 | });
57 | });
58 |
59 | describe('success with info that is transformed', function() {
60 | function Strategy() {
61 | }
62 | Strategy.prototype.authenticate = function(req) {
63 | var user = { id: '1', username: 'jaredhanson' };
64 | this.success(user, { clientId: '123', scope: 'read' });
65 | };
66 |
67 | var passport = new Passport();
68 | passport.use('success', new Strategy());
69 | passport.transformAuthInfo(function(info, done) {
70 | done(null, { clientId: info.clientId, client: { name: 'Foo' }, scope: info.scope });
71 | });
72 |
73 | var request, error;
74 |
75 | before(function(done) {
76 | chai.connect.use(authenticate(passport, 'success'))
77 | .req(function(req) {
78 | request = req;
79 |
80 | req.logIn = function(user, options, done) {
81 | this.user = user;
82 | done();
83 | };
84 | })
85 | .next(function(err) {
86 | error = err;
87 | done();
88 | })
89 | .dispatch();
90 | });
91 |
92 | it('should not error', function() {
93 | expect(error).to.be.undefined;
94 | });
95 |
96 | it('should set user', function() {
97 | expect(request.user).to.be.an('object');
98 | expect(request.user.id).to.equal('1');
99 | expect(request.user.username).to.equal('jaredhanson');
100 | });
101 |
102 | it('should set authInfo', function() {
103 | expect(request.authInfo).to.be.an('object');
104 | expect(Object.keys(request.authInfo)).to.have.length(3);
105 | expect(request.authInfo.clientId).to.equal('123');
106 | expect(request.authInfo.client.name).to.equal('Foo');
107 | expect(request.authInfo.scope).to.equal('read');
108 | });
109 | });
110 |
111 | describe('success with info, but transform that encounters an error', function() {
112 | function Strategy() {
113 | }
114 | Strategy.prototype.authenticate = function(req) {
115 | var user = { id: '1', username: 'jaredhanson' };
116 | this.success(user, { clientId: '123', scope: 'read' });
117 | };
118 |
119 | var passport = new Passport();
120 | passport.use('success', new Strategy());
121 | passport.transformAuthInfo(function(info, done) {
122 | done(new Error('something went wrong'));
123 | });
124 |
125 | var request, error;
126 |
127 | before(function(done) {
128 | chai.connect.use(authenticate(passport, 'success'))
129 | .req(function(req) {
130 | request = req;
131 |
132 | req.logIn = function(user, options, done) {
133 | this.user = user;
134 | done();
135 | };
136 | })
137 | .next(function(err) {
138 | error = err;
139 | done();
140 | })
141 | .dispatch();
142 | });
143 |
144 | it('should error', function() {
145 | expect(error).to.be.an.instanceOf(Error);
146 | expect(error.message).to.equal('something went wrong');
147 | });
148 |
149 | it('should set user', function() {
150 | expect(request.user).to.be.an('object');
151 | expect(request.user.id).to.equal('1');
152 | expect(request.user.username).to.equal('jaredhanson');
153 | });
154 |
155 | it('should not set authInfo', function() {
156 | expect(request.authInfo).to.be.undefined;
157 | });
158 | });
159 |
160 | describe('success with info, but option that disables info', function() {
161 | function Strategy() {
162 | }
163 | Strategy.prototype.authenticate = function(req) {
164 | var user = { id: '1', username: 'jaredhanson' };
165 | this.success(user, { clientId: '123', scope: 'read' });
166 | };
167 |
168 | var passport = new Passport();
169 | passport.use('success', new Strategy());
170 |
171 | var request, error;
172 |
173 | before(function(done) {
174 | chai.connect.use(authenticate(passport, 'success', { authInfo: false }))
175 | .req(function(req) {
176 | request = req;
177 |
178 | req.logIn = function(user, options, done) {
179 | this.user = user;
180 | done();
181 | };
182 | })
183 | .next(function(err) {
184 | error = err;
185 | done();
186 | })
187 | .dispatch();
188 | });
189 |
190 | it('should not error', function() {
191 | expect(error).to.be.undefined;
192 | });
193 |
194 | it('should set user', function() {
195 | expect(request.user).to.be.an('object');
196 | expect(request.user.id).to.equal('1');
197 | expect(request.user.username).to.equal('jaredhanson');
198 | });
199 |
200 | it('should not set authInfo', function() {
201 | expect(request.authInfo).to.be.undefined;
202 | });
203 | });
204 |
205 | });
206 |
--------------------------------------------------------------------------------
/test/middleware/authenticate.success.message.test.js:
--------------------------------------------------------------------------------
1 | /* global describe, it, expect, before */
2 |
3 | var chai = require('chai')
4 | , authenticate = require('../../lib/middleware/authenticate')
5 | , Passport = require('../..').Passport;
6 |
7 |
8 | describe('middleware/authenticate', function() {
9 |
10 | describe('success with message set by route', function() {
11 | function Strategy() {
12 | }
13 | Strategy.prototype.authenticate = function(req, options) {
14 | var user = { id: '1', username: 'jaredhanson' };
15 | this.success(user, { message: 'Welcome!' });
16 | };
17 |
18 | var passport = new Passport();
19 | passport.use('success', new Strategy());
20 |
21 | var request, response;
22 |
23 | before(function(done) {
24 | chai.connect.use('express', authenticate(passport, 'success', { successMessage: 'Login complete',
25 | successRedirect: 'http://www.example.com/account' }))
26 | .req(function(req) {
27 | request = req;
28 | req.session = {};
29 |
30 | req.logIn = function(user, options, done) {
31 | this.user = user;
32 | done();
33 | };
34 | })
35 | .end(function(res) {
36 | response = res;
37 | done();
38 | })
39 | .dispatch();
40 | });
41 |
42 | it('should set user', function() {
43 | expect(request.user).to.be.an('object');
44 | expect(request.user.id).to.equal('1');
45 | expect(request.user.username).to.equal('jaredhanson');
46 | });
47 |
48 | it('should add message to session', function() {
49 | expect(request.session.messages).to.have.length(1);
50 | expect(request.session.messages[0]).to.equal('Login complete');
51 | });
52 |
53 | it('should redirect', function() {
54 | expect(response.statusCode).to.equal(302);
55 | expect(response.getHeader('Location')).to.equal('http://www.example.com/account');
56 | });
57 | });
58 |
59 | describe('success with message set by route that is added to messages', function() {
60 | function Strategy() {
61 | }
62 | Strategy.prototype.authenticate = function(req, options) {
63 | var user = { id: '1', username: 'jaredhanson' };
64 | this.success(user, { message: 'Welcome!' });
65 | };
66 |
67 | var passport = new Passport();
68 | passport.use('success', new Strategy());
69 |
70 | var request, response;
71 |
72 | before(function(done) {
73 | chai.connect.use('express', authenticate(passport, 'success', { successMessage: 'Login complete',
74 | successRedirect: 'http://www.example.com/account' }))
75 | .req(function(req) {
76 | request = req;
77 | req.session = {};
78 | req.session.messages = [ 'I exist!' ];
79 |
80 | req.logIn = function(user, options, done) {
81 | this.user = user;
82 | done();
83 | };
84 | })
85 | .end(function(res) {
86 | response = res;
87 | done();
88 | })
89 | .dispatch();
90 | });
91 |
92 | it('should set user', function() {
93 | expect(request.user).to.be.an('object');
94 | expect(request.user.id).to.equal('1');
95 | expect(request.user.username).to.equal('jaredhanson');
96 | });
97 |
98 | it('should add message to session', function() {
99 | expect(request.session.messages).to.have.length(2);
100 | expect(request.session.messages[0]).to.equal('I exist!');
101 | expect(request.session.messages[1]).to.equal('Login complete');
102 | });
103 |
104 | it('should redirect', function() {
105 | expect(response.statusCode).to.equal(302);
106 | expect(response.getHeader('Location')).to.equal('http://www.example.com/account');
107 | });
108 | });
109 |
110 | describe('success with message set by strategy', function() {
111 | function Strategy() {
112 | }
113 | Strategy.prototype.authenticate = function(req, options) {
114 | var user = { id: '1', username: 'jaredhanson' };
115 | this.success(user, { message: 'Welcome!' });
116 | };
117 |
118 | var passport = new Passport();
119 | passport.use('success', new Strategy());
120 |
121 | var request, response;
122 |
123 | before(function(done) {
124 | chai.connect.use('express', authenticate(passport, 'success', { successMessage: true,
125 | successRedirect: 'http://www.example.com/account' }))
126 | .req(function(req) {
127 | request = req;
128 | req.session = {};
129 |
130 | req.logIn = function(user, options, done) {
131 | this.user = user;
132 | done();
133 | };
134 | })
135 | .end(function(res) {
136 | response = res;
137 | done();
138 | })
139 | .dispatch();
140 | });
141 |
142 | it('should set user', function() {
143 | expect(request.user).to.be.an('object');
144 | expect(request.user.id).to.equal('1');
145 | expect(request.user.username).to.equal('jaredhanson');
146 | });
147 |
148 | it('should add message to session', function() {
149 | expect(request.session.messages).to.have.length(1);
150 | expect(request.session.messages[0]).to.equal('Welcome!');
151 | });
152 |
153 | it('should redirect', function() {
154 | expect(response.statusCode).to.equal(302);
155 | expect(response.getHeader('Location')).to.equal('http://www.example.com/account');
156 | });
157 | });
158 |
159 | describe('success with message set by strategy with extra info', function() {
160 | function Strategy() {
161 | }
162 | Strategy.prototype.authenticate = function(req, options) {
163 | var user = { id: '1', username: 'jaredhanson' };
164 | this.success(user, { message: 'Welcome!', scope: 'read' });
165 | };
166 |
167 | var passport = new Passport();
168 | passport.use('success', new Strategy());
169 |
170 | var request, response;
171 |
172 | before(function(done) {
173 | chai.connect.use('express', authenticate(passport, 'success', { successMessage: true,
174 | successRedirect: 'http://www.example.com/account' }))
175 | .req(function(req) {
176 | request = req;
177 | req.session = {};
178 |
179 | req.logIn = function(user, options, done) {
180 | this.user = user;
181 | done();
182 | };
183 | })
184 | .end(function(res) {
185 | response = res;
186 | done();
187 | })
188 | .dispatch();
189 | });
190 |
191 | it('should set user', function() {
192 | expect(request.user).to.be.an('object');
193 | expect(request.user.id).to.equal('1');
194 | expect(request.user.username).to.equal('jaredhanson');
195 | });
196 |
197 | it('should add message to session', function() {
198 | expect(request.session.messages).to.have.length(1);
199 | expect(request.session.messages[0]).to.equal('Welcome!');
200 | });
201 |
202 | it('should redirect', function() {
203 | expect(response.statusCode).to.equal(302);
204 | expect(response.getHeader('Location')).to.equal('http://www.example.com/account');
205 | });
206 | });
207 |
208 | });
209 |
--------------------------------------------------------------------------------
/test/middleware/authenticate.success.multi.test.js:
--------------------------------------------------------------------------------
1 | /* global describe, it, expect, before */
2 | /* jshint expr: true */
3 |
4 | var chai = require('chai')
5 | , authenticate = require('../../lib/middleware/authenticate')
6 | , Passport = require('../..').Passport;
7 |
8 |
9 | describe('middleware/authenticate', function() {
10 |
11 | describe('with multiple strategies, the first of which succeeds', function() {
12 | function StrategyA() {
13 | }
14 | StrategyA.prototype.authenticate = function(req) {
15 | this.success({ username: 'bob-a' });
16 | };
17 |
18 | function StrategyB() {
19 | }
20 | StrategyB.prototype.authenticate = function(req) {
21 | this.success({ username: 'bob-b' });
22 | };
23 |
24 | var passport = new Passport();
25 | passport.use('a', new StrategyA());
26 | passport.use('b', new StrategyB());
27 |
28 | var request, error;
29 |
30 | before(function(done) {
31 | chai.connect.use(authenticate(passport, ['a', 'b']))
32 | .req(function(req) {
33 | request = req;
34 |
35 | req.logIn = function(user, options, done) {
36 | this.user = user;
37 | done();
38 | };
39 | })
40 | .next(function(err) {
41 | error = err;
42 | done();
43 | })
44 | .dispatch();
45 | });
46 |
47 | it('should not error', function() {
48 | expect(error).to.be.undefined;
49 | });
50 |
51 | it('should set user', function() {
52 | expect(request.user).to.be.an('object');
53 | expect(request.user.username).to.equal('bob-a');
54 | });
55 | });
56 |
57 | describe('with multiple strategies, the second of which succeeds', function() {
58 | function StrategyA() {
59 | }
60 | StrategyA.prototype.authenticate = function(req) {
61 | this.fail('A challenge');
62 | };
63 |
64 | function StrategyB() {
65 | }
66 | StrategyB.prototype.authenticate = function(req) {
67 | this.success({ username: 'bob-b' });
68 | };
69 |
70 | var passport = new Passport();
71 | passport.use('a', new StrategyA());
72 | passport.use('b', new StrategyB());
73 |
74 | var request, error;
75 |
76 | before(function(done) {
77 | chai.connect.use(authenticate(passport, ['a', 'b']))
78 | .req(function(req) {
79 | request = req;
80 |
81 | req.logIn = function(user, options, done) {
82 | this.user = user;
83 | done();
84 | };
85 | })
86 | .next(function(err) {
87 | error = err;
88 | done();
89 | })
90 | .dispatch();
91 | });
92 |
93 | it('should not error', function() {
94 | expect(error).to.be.undefined;
95 | });
96 |
97 | it('should set user', function() {
98 | expect(request.user).to.be.an('object');
99 | expect(request.user.username).to.equal('bob-b');
100 | });
101 | });
102 |
103 | });
104 |
--------------------------------------------------------------------------------
/test/middleware/authenticate.success.test.js:
--------------------------------------------------------------------------------
1 | /* global describe, it, expect, before */
2 | /* jshint expr: true */
3 |
4 | var chai = require('chai')
5 | , authenticate = require('../../lib/middleware/authenticate')
6 | , Passport = require('../..').Passport;
7 |
8 |
9 | describe('middleware/authenticate', function() {
10 |
11 | describe('success', function() {
12 | function Strategy() {
13 | }
14 | Strategy.prototype.authenticate = function(req) {
15 | var user = { id: '1', username: 'jaredhanson' };
16 | this.success(user);
17 | };
18 |
19 | var passport = new Passport();
20 | passport.use('success', new Strategy());
21 |
22 | var request, error;
23 |
24 | before(function(done) {
25 | chai.connect.use(authenticate(passport, 'success'))
26 | .req(function(req) {
27 | request = req;
28 |
29 | req.logIn = function(user, options, done) {
30 | this.user = user;
31 | done();
32 | };
33 | })
34 | .next(function(err) {
35 | error = err;
36 | done();
37 | })
38 | .dispatch();
39 | });
40 |
41 | it('should not error', function() {
42 | expect(error).to.be.undefined;
43 | });
44 |
45 | it('should set user', function() {
46 | expect(request.user).to.be.an('object');
47 | expect(request.user.id).to.equal('1');
48 | expect(request.user.username).to.equal('jaredhanson');
49 | });
50 |
51 | it('should set authInfo', function() {
52 | expect(request.authInfo).to.be.an('object');
53 | expect(Object.keys(request.authInfo)).to.have.length(0);
54 | });
55 | });
56 |
57 | describe('success that assigns a specific property', function() {
58 | function Strategy() {
59 | }
60 | Strategy.prototype.authenticate = function(req) {
61 | var user = { id: '1', username: 'jaredhanson' };
62 | this.success(user);
63 | };
64 |
65 | var passport = new Passport();
66 | passport.use('success', new Strategy());
67 |
68 | var request, error;
69 |
70 | before(function(done) {
71 | chai.connect.use(authenticate(passport, 'success', { assignProperty: 'account' }))
72 | .req(function(req) {
73 | request = req;
74 |
75 | req.logIn = function(user, options, done) {
76 | this.user = user;
77 | done();
78 | };
79 | })
80 | .next(function(err) {
81 | error = err;
82 | done();
83 | })
84 | .dispatch();
85 | });
86 |
87 | it('should not error', function() {
88 | expect(error).to.be.undefined;
89 | });
90 |
91 | it('should not set user', function() {
92 | expect(request.user).to.be.undefined;
93 | });
94 |
95 | it('should set account', function() {
96 | expect(request.account).to.be.an('object');
97 | expect(request.account.id).to.equal('1');
98 | expect(request.account.username).to.equal('jaredhanson');
99 | });
100 |
101 | it('should set authInfo to empty object', function() {
102 | expect(request.authInfo).to.deep.equal({});
103 | });
104 | });
105 |
106 | describe('success that assigns a specific property with authInfo disabled', function() {
107 | function Strategy() {
108 | }
109 | Strategy.prototype.authenticate = function(req) {
110 | var user = { id: '1', username: 'jaredhanson' };
111 | this.success(user);
112 | };
113 |
114 | var passport = new Passport();
115 | passport.use('success', new Strategy());
116 |
117 | var request, error;
118 |
119 | before(function(done) {
120 | chai.connect.use(authenticate(passport, 'success', { assignProperty: 'account', authInfo: false }))
121 | .req(function(req) {
122 | request = req;
123 |
124 | req.logIn = function(user, options, done) {
125 | this.user = user;
126 | done();
127 | };
128 | })
129 | .next(function(err) {
130 | error = err;
131 | done();
132 | })
133 | .dispatch();
134 | });
135 |
136 | it('should not error', function() {
137 | expect(error).to.be.undefined;
138 | });
139 |
140 | it('should not set user', function() {
141 | expect(request.user).to.be.undefined;
142 | });
143 |
144 | it('should set account', function() {
145 | expect(request.account).to.be.an('object');
146 | expect(request.account.id).to.equal('1');
147 | expect(request.account.username).to.equal('jaredhanson');
148 | });
149 |
150 | it('should not set authInfo', function() {
151 | expect(request.authInfo).to.be.undefined;
152 | });
153 | });
154 |
155 | describe('success with strategy-specific options', function() {
156 | function Strategy() {
157 | }
158 | Strategy.prototype.authenticate = function(req, options) {
159 | var user = { id: '1', username: 'jaredhanson' };
160 | if (options.scope == 'email') {
161 | user.email = 'jaredhanson@example.com';
162 | }
163 | this.success(user);
164 | };
165 |
166 | var passport = new Passport();
167 | passport.use('success', new Strategy());
168 |
169 | var request, error;
170 |
171 | before(function(done) {
172 | chai.connect.use(authenticate(passport, 'success', { scope: 'email' }))
173 | .req(function(req) {
174 | request = req;
175 |
176 | req.logIn = function(user, options, done) {
177 | if (options.scope != 'email') { return done(new Error('invalid options')); }
178 | this.user = user;
179 | done();
180 | };
181 | })
182 | .next(function(err) {
183 | error = err;
184 | done();
185 | })
186 | .dispatch();
187 | });
188 |
189 | it('should not error', function() {
190 | expect(error).to.be.undefined;
191 | });
192 |
193 | it('should set user', function() {
194 | expect(request.user).to.be.an('object');
195 | expect(request.user.id).to.equal('1');
196 | expect(request.user.username).to.equal('jaredhanson');
197 | expect(request.user.email).to.equal('jaredhanson@example.com');
198 | });
199 |
200 | it('should set authInfo', function() {
201 | expect(request.authInfo).to.be.an('object');
202 | expect(Object.keys(request.authInfo)).to.have.length(0);
203 | });
204 | });
205 |
206 | describe('success with redirect', function() {
207 | function Strategy() {
208 | }
209 | Strategy.prototype.authenticate = function(req, options) {
210 | var user = { id: '1', username: 'jaredhanson' };
211 | this.success(user);
212 | };
213 |
214 | var passport = new Passport();
215 | passport.use('success', new Strategy());
216 |
217 | var request, response;
218 |
219 | before(function(done) {
220 | chai.connect.use('express', authenticate(passport, 'success', { successRedirect: 'http://www.example.com/account' }))
221 | .req(function(req) {
222 | request = req;
223 |
224 | req.logIn = function(user, options, done) {
225 | this.user = user;
226 | done();
227 | };
228 | })
229 | .end(function(res) {
230 | response = res;
231 | done();
232 | })
233 | .dispatch();
234 | });
235 |
236 | it('should set user', function() {
237 | expect(request.user).to.be.an('object');
238 | expect(request.user.id).to.equal('1');
239 | expect(request.user.username).to.equal('jaredhanson');
240 | });
241 |
242 | it('should set authInfo', function() {
243 | expect(request.authInfo).to.be.an('object');
244 | expect(Object.keys(request.authInfo)).to.have.length(0);
245 | });
246 |
247 | it('should redirect', function() {
248 | expect(response.statusCode).to.equal(302);
249 | expect(response.getHeader('Location')).to.equal('http://www.example.com/account');
250 | });
251 | });
252 |
253 | describe('success with return to previous location', function() {
254 | function Strategy() {
255 | }
256 | Strategy.prototype.authenticate = function(req, options) {
257 | var user = { id: '1', username: 'jaredhanson' };
258 | this.success(user);
259 | };
260 |
261 | var passport = new Passport();
262 | passport.use('success', new Strategy());
263 |
264 | var request, response;
265 |
266 | before(function(done) {
267 | chai.connect.use('express', authenticate(passport, 'success', { successReturnToOrRedirect: 'http://www.example.com/default' }))
268 | .req(function(req) {
269 | request = req;
270 | req.session = { returnTo: 'http://www.example.com/return' };
271 |
272 | req.logIn = function(user, options, done) {
273 | this.user = user;
274 | done();
275 | };
276 | })
277 | .end(function(res) {
278 | response = res;
279 | done();
280 | })
281 | .dispatch();
282 | });
283 |
284 | it('should set user', function() {
285 | expect(request.user).to.be.an('object');
286 | expect(request.user.id).to.equal('1');
287 | expect(request.user.username).to.equal('jaredhanson');
288 | });
289 |
290 | it('should set authInfo', function() {
291 | expect(request.authInfo).to.be.an('object');
292 | expect(Object.keys(request.authInfo)).to.have.length(0);
293 | });
294 |
295 | it('should redirect', function() {
296 | expect(response.statusCode).to.equal(302);
297 | expect(response.getHeader('Location')).to.equal('http://www.example.com/return');
298 | });
299 |
300 | it('should move return to from session', function() {
301 | expect(request.session.returnTo).to.be.undefined;
302 | });
303 | });
304 |
305 | describe('success with return to default location', function() {
306 | function Strategy() {
307 | }
308 | Strategy.prototype.authenticate = function(req, options) {
309 | var user = { id: '1', username: 'jaredhanson' };
310 | this.success(user);
311 | };
312 |
313 | var passport = new Passport();
314 | passport.use('success', new Strategy());
315 |
316 | var request, response;
317 |
318 | before(function(done) {
319 | chai.connect.use('express', authenticate(passport, 'success', { successReturnToOrRedirect: 'http://www.example.com/default' }))
320 | .req(function(req) {
321 | request = req;
322 |
323 | req.logIn = function(user, options, done) {
324 | this.user = user;
325 | done();
326 | };
327 | })
328 | .end(function(res) {
329 | response = res;
330 | done();
331 | })
332 | .dispatch();
333 | });
334 |
335 | it('should set user', function() {
336 | expect(request.user).to.be.an('object');
337 | expect(request.user.id).to.equal('1');
338 | expect(request.user.username).to.equal('jaredhanson');
339 | });
340 |
341 | it('should set authInfo', function() {
342 | expect(request.authInfo).to.be.an('object');
343 | expect(Object.keys(request.authInfo)).to.have.length(0);
344 | });
345 |
346 | it('should redirect', function() {
347 | expect(response.statusCode).to.equal(302);
348 | expect(response.getHeader('Location')).to.equal('http://www.example.com/default');
349 | });
350 | });
351 |
352 | describe('success, but login that encounters an error', function() {
353 | function Strategy() {
354 | }
355 | Strategy.prototype.authenticate = function(req) {
356 | var user = { id: '1', username: 'jaredhanson' };
357 | this.success(user);
358 | };
359 |
360 | var passport = new Passport();
361 | passport.use('success', new Strategy());
362 |
363 | var request, error;
364 |
365 | before(function(done) {
366 | chai.connect.use(authenticate(passport, 'success'))
367 | .req(function(req) {
368 | request = req;
369 |
370 | req.logIn = function(user, options, done) {
371 | done(new Error('something went wrong'));
372 | };
373 | })
374 | .next(function(err) {
375 | error = err;
376 | done();
377 | })
378 | .dispatch();
379 | });
380 |
381 | it('should error', function() {
382 | expect(error).to.be.an.instanceOf(Error);
383 | expect(error.message).to.equal('something went wrong');
384 | });
385 |
386 | it('should not set user', function() {
387 | expect(request.user).to.be.undefined;
388 | });
389 |
390 | it('should not set authInfo', function() {
391 | expect(request.authInfo).to.be.undefined;
392 | });
393 | });
394 |
395 | });
396 |
--------------------------------------------------------------------------------
/test/middleware/authenticate.test.js:
--------------------------------------------------------------------------------
1 | /* global describe, it, expect, before */
2 | /* jshint expr: true */
3 |
4 | var chai = require('chai')
5 | , authenticate = require('../../lib/middleware/authenticate')
6 | , Passport = require('../..').Passport;
7 |
8 |
9 | describe('middleware/authenticate', function() {
10 |
11 | it('should be named authenticate', function() {
12 | expect(authenticate().name).to.equal('authenticate');
13 | });
14 |
15 | describe('with unknown strategy', function() {
16 | var passport = new Passport();
17 |
18 | var request, error;
19 |
20 | before(function(done) {
21 | chai.connect.use(authenticate(passport, 'foo'))
22 | .req(function(req) {
23 | request = req;
24 |
25 | req.logIn = function(user, options, done) {
26 | this.user = user;
27 | done();
28 | };
29 | })
30 | .next(function(err) {
31 | error = err;
32 | done();
33 | })
34 | .dispatch();
35 | });
36 |
37 | it('should error', function() {
38 | expect(error).to.be.an.instanceOf(Error);
39 | expect(error.message).to.equal('Unknown authentication strategy "foo"');
40 | });
41 |
42 | it('should not set user', function() {
43 | expect(request.user).to.be.undefined;
44 | });
45 |
46 | it('should not set authInfo', function() {
47 | expect(request.authInfo).to.be.undefined;
48 | });
49 | });
50 |
51 | });
52 |
--------------------------------------------------------------------------------
/test/middleware/initialize.test.js:
--------------------------------------------------------------------------------
1 | /* global describe, it, expect, before */
2 | /* jshint expr: true */
3 |
4 | var chai = require('chai')
5 | , initialize = require('../../lib/middleware/initialize')
6 | , Passport = require('../..').Passport;
7 |
8 |
9 | describe('middleware/initialize', function() {
10 |
11 | it('should be named initialize', function() {
12 | expect(initialize().name).to.equal('initialize');
13 | });
14 |
15 | describe('handling a request without a session', function() {
16 | var passport = new Passport();
17 | var request, error;
18 |
19 | before(function(done) {
20 | chai.connect.use(initialize(passport))
21 | .req(function(req) {
22 | request = req;
23 | })
24 | .next(function(err) {
25 | error = err;
26 | done();
27 | })
28 | .dispatch();
29 | });
30 |
31 | it('should not error', function() {
32 | expect(error).to.be.undefined;
33 | });
34 |
35 | it('should expose authenticator on internal request property', function() {
36 | expect(request._passport).to.be.an('object');
37 | expect(request._passport.instance).to.be.an.instanceOf(Passport);
38 | expect(request._passport.instance).to.equal(passport);
39 | expect(request._passport.instance._sm).to.be.an('object');
40 | expect(request._passport.instance._userProperty).to.equal('user');
41 | });
42 | });
43 |
44 | describe('handling a request with a new session', function() {
45 | var passport = new Passport();
46 | var request, error;
47 |
48 | before(function(done) {
49 | chai.connect.use(initialize(passport))
50 | .req(function(req) {
51 | request = req;
52 |
53 | req.session = {};
54 | })
55 | .next(function(err) {
56 | error = err;
57 | done();
58 | })
59 | .dispatch();
60 | });
61 |
62 | it('should not error', function() {
63 | expect(error).to.be.undefined;
64 | });
65 |
66 | it('should not initialize namespace within session', function() {
67 | expect(request.session.passport).to.be.undefined;
68 | });
69 |
70 | it('should expose authenticator on internal request property', function() {
71 | expect(request._passport).to.be.an('object');
72 | expect(request._passport.instance).to.be.an.instanceOf(Passport);
73 | expect(request._passport.instance).to.equal(passport);
74 | expect(request._passport.instance._sm).to.be.an('object');
75 | expect(request._passport.instance._userProperty).to.equal('user');
76 | });
77 | });
78 |
79 | describe('handling a request with an existing session', function() {
80 | var passport = new Passport();
81 | var request, error;
82 |
83 | before(function(done) {
84 | chai.connect.use(initialize(passport))
85 | .req(function(req) {
86 | request = req;
87 |
88 | req.session = {};
89 | req.session.passport = {};
90 | req.session.passport.user = '123456';
91 | })
92 | .next(function(err) {
93 | error = err;
94 | done();
95 | })
96 | .dispatch();
97 | });
98 |
99 | it('should not error', function() {
100 | expect(error).to.be.undefined;
101 | });
102 |
103 | it('should maintain data within session', function() {
104 | expect(request.session.passport).to.be.an('object');
105 | expect(Object.keys(request.session.passport)).to.have.length(1);
106 | expect(request.session.passport.user).to.equal('123456');
107 | });
108 |
109 | it('should expose authenticator on internal request property', function() {
110 | expect(request._passport).to.be.an('object');
111 | expect(request._passport.instance).to.be.an.instanceOf(Passport);
112 | expect(request._passport.instance).to.equal(passport);
113 | expect(request._passport.instance._sm).to.be.an('object');
114 | expect(request._passport.instance._userProperty).to.equal('user');
115 | });
116 | });
117 |
118 | describe('handling a request with an existing session using custom session key', function() {
119 | var passport = new Passport();
120 | passport._key = 'authentication';
121 | var request, error;
122 |
123 | before(function(done) {
124 | chai.connect.use(initialize(passport))
125 | .req(function(req) {
126 | request = req;
127 |
128 | req.session = {};
129 | req.session.authentication = {};
130 | req.session.authentication.user = '123456';
131 | })
132 | .next(function(err) {
133 | error = err;
134 | done();
135 | })
136 | .dispatch();
137 | });
138 |
139 | it('should not error', function() {
140 | expect(error).to.be.undefined;
141 | });
142 |
143 | it('should maintain data within session', function() {
144 | expect(request.session.authentication).to.be.an('object');
145 | expect(Object.keys(request.session.authentication)).to.have.length(1);
146 | expect(request.session.authentication.user).to.equal('123456');
147 | });
148 |
149 | it('should expose authenticator on internal request property', function() {
150 | expect(request._passport).to.be.an('object');
151 | expect(request._passport.instance).to.be.an.instanceOf(Passport);
152 | expect(request._passport.instance).to.equal(passport);
153 | expect(request._passport.instance._sm).to.be.an('object');
154 | expect(request._passport.instance._userProperty).to.equal('user');
155 | });
156 | });
157 |
158 | describe('handling a request with a new session without compat mode', function() {
159 | var passport = new Passport();
160 | var request, error;
161 |
162 | before(function(done) {
163 | chai.connect.use(initialize(passport, { compat: false }))
164 | .req(function(req) {
165 | request = req;
166 |
167 | req.session = {};
168 | })
169 | .next(function(err) {
170 | error = err;
171 | done();
172 | })
173 | .dispatch();
174 | });
175 |
176 | it('should not error', function() {
177 | expect(error).to.be.undefined;
178 | });
179 |
180 | it('should not initialize namespace within session', function() {
181 | expect(request.session.passport).to.be.undefined;
182 | });
183 |
184 | it('should expose authenticator on internal request property', function() {
185 | expect(request._passport).to.be.undefined;
186 | });
187 | });
188 |
189 | });
190 |
--------------------------------------------------------------------------------
/test/package.test.js:
--------------------------------------------------------------------------------
1 | /* global describe, it, expect */
2 |
3 | var passport = require('..');
4 |
5 | describe('passport', function() {
6 |
7 | it('should expose singleton authenticator', function() {
8 | expect(passport).to.be.an('object');
9 | expect(passport).to.be.an.instanceOf(passport.Authenticator);
10 | });
11 |
12 | it('should export constructors', function() {
13 | expect(passport.Authenticator).to.equal(passport.Passport);
14 | expect(passport.Authenticator).to.be.a('function');
15 | expect(passport.Strategy).to.be.a('function');
16 | });
17 |
18 | it('should export strategies', function() {
19 | expect(passport.strategies.SessionStrategy).to.be.a('function');
20 | });
21 |
22 | });
23 |
--------------------------------------------------------------------------------
/test/strategies/session.pause.test.js:
--------------------------------------------------------------------------------
1 | /* global describe, it, expect, before */
2 | /* jshint expr: true */
3 |
4 | var chai = require('chai');
5 |
6 |
7 | describe('SessionStrategy', function() {
8 |
9 | describe('handling a request with a login session, pausing for deserialization', function() {
10 | var spy = [];
11 |
12 | var pause = function() {
13 | spy.push({ context: this, args: [].slice.call(arguments) });
14 | return { resume: function() { spy.push({ context: this, args: [].slice.call(arguments) }); } };
15 | }
16 |
17 |
18 | var SessionStrategy = $require('../../lib/strategies/session', { pause: pause });
19 | var strategy = new SessionStrategy(function(user, req, done) {
20 | done(null, { id: user });
21 | });
22 |
23 | var request, pass = false;
24 |
25 | before(function(done) {
26 | chai.passport.use(strategy)
27 | .pass(function() {
28 | pass = true;
29 | done();
30 | })
31 | .req(function(req) {
32 | request = req;
33 |
34 | req._passport = {};
35 | req._passport.instance = {};
36 | req.session = {};
37 | req.session['passport'] = {};
38 | req.session['passport'].user = '123456';
39 | })
40 | .authenticate({ pauseStream: true });
41 | });
42 |
43 | it('should spy correctly', function() {
44 | expect(spy).to.have.length(2);
45 | });
46 |
47 | it('should pass', function() {
48 | expect(pass).to.be.true;
49 | });
50 |
51 | it('should set user on request', function() {
52 | expect(request.user).to.be.an('object');
53 | expect(request.user.id).to.equal('123456');
54 | });
55 |
56 | it('should maintain session', function() {
57 | expect(request.session['passport']).to.be.an('object');
58 | expect(request.session['passport'].user).to.equal('123456');
59 | });
60 |
61 | it('should pause request', function() {
62 | var s0 = spy[0];
63 | expect(s0.args[0]).to.equal(request);
64 | });
65 |
66 | it('should resume request', function() {
67 | var s1 = spy[1];
68 | expect(s1.args[0]).to.equal(undefined);
69 | });
70 | });
71 |
72 | describe('handling a request with a login session that has been invalidated, pausing for deserialization', function() {
73 | var spy = [];
74 |
75 | var pause = function() {
76 | spy.push({ context: this, args: [].slice.call(arguments) });
77 | return { resume: function() { spy.push({ context: this, args: [].slice.call(arguments) }); } };
78 | }
79 |
80 |
81 | var SessionStrategy = $require('../../lib/strategies/session', { pause: pause });
82 | var strategy = new SessionStrategy(function(user, req, done) {
83 | done(null, false);
84 | });
85 |
86 | var request, pass = false;
87 |
88 | before(function(done) {
89 | chai.passport.use(strategy)
90 | .pass(function() {
91 | pass = true;
92 | done();
93 | })
94 | .req(function(req) {
95 | request = req;
96 |
97 | req._passport = {};
98 | req._passport.instance = {};
99 | req.session = {};
100 | req.session['passport'] = {};
101 | req.session['passport'].user = '123456';
102 | })
103 | .authenticate({ pauseStream: true });
104 | });
105 |
106 | it('should spy correctly', function() {
107 | expect(spy).to.have.length(2);
108 | });
109 |
110 | it('should pass', function() {
111 | expect(pass).to.be.true;
112 | });
113 |
114 | it('should not set user on request', function() {
115 | expect(request.user).to.be.undefined;
116 | });
117 |
118 | it('should remove user from session', function() {
119 | expect(request.session['passport']).to.be.an('object');
120 | expect(request.session['passport'].user).to.be.undefined;
121 | });
122 |
123 | it('should pause request', function() {
124 | var s0 = spy[0];
125 | expect(s0.args[0]).to.equal(request);
126 | });
127 |
128 | it('should resume request', function() {
129 | var s1 = spy[1];
130 | expect(s1.args[0]).to.equal(undefined);
131 | });
132 | });
133 |
134 | });
135 |
--------------------------------------------------------------------------------
/test/strategies/session.test.js:
--------------------------------------------------------------------------------
1 | /* global describe, it, expect, before */
2 | /* jshint expr: true */
3 |
4 | var chai = require('chai')
5 | , SessionStrategy = require('../../lib/strategies/session');
6 |
7 |
8 | describe('SessionStrategy', function() {
9 |
10 | var strategy = new SessionStrategy();
11 |
12 | it('should be named session', function() {
13 | expect(strategy.name).to.equal('session');
14 | });
15 |
16 | describe('handling a request without a login session', function() {
17 | var request, pass = false;
18 |
19 | before(function(done) {
20 | chai.passport.use(strategy)
21 | .pass(function() {
22 | pass = true;
23 | done();
24 | })
25 | .req(function(req) {
26 | request = req;
27 |
28 | req._passport = {};
29 | req.session = {};
30 | req.session['passport'] = {};
31 | })
32 | .authenticate();
33 | });
34 |
35 | it('should pass', function() {
36 | expect(pass).to.be.true;
37 | });
38 |
39 | it('should not set user on request', function() {
40 | expect(request.user).to.be.undefined;
41 | });
42 | });
43 |
44 | describe('handling a request with a login session', function() {
45 | var strategy = new SessionStrategy(function(user, req, done) {
46 | done(null, { id: user });
47 | });
48 |
49 | var request, pass = false;
50 |
51 | before(function(done) {
52 | chai.passport.use(strategy)
53 | .pass(function() {
54 | pass = true;
55 | done();
56 | })
57 | .req(function(req) {
58 | request = req;
59 |
60 | req._passport = {};
61 | req._passport.instance = {};
62 | req.session = {};
63 | req.session['passport'] = {};
64 | req.session['passport'].user = '123456';
65 | })
66 | .authenticate();
67 | });
68 |
69 | it('should pass', function() {
70 | expect(pass).to.be.true;
71 | });
72 |
73 | it('should set user on request', function() {
74 | expect(request.user).to.be.an('object');
75 | expect(request.user.id).to.equal('123456');
76 | });
77 |
78 | it('should maintain session', function() {
79 | expect(request.session['passport']).to.be.an('object');
80 | expect(request.session['passport'].user).to.equal('123456');
81 | });
82 | });
83 |
84 | describe('handling a request with a login session serialized to 0', function() {
85 | var strategy = new SessionStrategy(function(user, req, done) {
86 | done(null, { id: user });
87 | });
88 |
89 | var request, pass = false;
90 |
91 | before(function(done) {
92 | chai.passport.use(strategy)
93 | .pass(function() {
94 | pass = true;
95 | done();
96 | })
97 | .req(function(req) {
98 | request = req;
99 |
100 | req._passport = {};
101 | req._passport.instance = {};
102 | req.session = {};
103 | req.session['passport'] = {};
104 | req.session['passport'].user = 0;
105 | })
106 | .authenticate();
107 | });
108 |
109 | it('should pass', function() {
110 | expect(pass).to.be.true;
111 | });
112 |
113 | it('should set user on request', function() {
114 | expect(request.user).to.be.an('object');
115 | expect(request.user.id).to.equal(0);
116 | });
117 |
118 | it('should maintain session', function() {
119 | expect(request.session['passport']).to.be.an('object');
120 | expect(request.session['passport'].user).to.equal(0);
121 | });
122 | });
123 |
124 | describe('handling a request with a login session that has been invalidated', function() {
125 | var strategy = new SessionStrategy(function(user, req, done) {
126 | done(null, false);
127 | });
128 |
129 | var request, pass = false;
130 |
131 | before(function(done) {
132 | chai.passport.use(strategy)
133 | .pass(function() {
134 | pass = true;
135 | done();
136 | })
137 | .req(function(req) {
138 | request = req;
139 |
140 | req._passport = {};
141 | req._passport.instance = {};
142 | req.session = {};
143 | req.session['passport'] = {};
144 | req.session['passport'].user = '123456';
145 | })
146 | .authenticate();
147 | });
148 |
149 | it('should pass', function() {
150 | expect(pass).to.be.true;
151 | });
152 |
153 | it('should not set user on request', function() {
154 | expect(request.user).to.be.undefined;
155 | });
156 |
157 | it('should remove user from session', function() {
158 | expect(request.session['passport']).to.be.an('object');
159 | expect(request.session['passport'].user).to.be.undefined;
160 | });
161 | });
162 |
163 | describe('handling a request with a login session and setting custom user property', function() {
164 | var strategy = new SessionStrategy(function(user, req, done) {
165 | done(null, { id: user });
166 | });
167 |
168 | var request, pass = false;
169 |
170 | before(function(done) {
171 | chai.passport.use(strategy)
172 | .pass(function() {
173 | pass = true;
174 | done();
175 | })
176 | .req(function(req) {
177 | request = req;
178 |
179 | req._passport = {};
180 | req._passport.instance = {};
181 | req._userProperty = 'currentUser';
182 | req.session = {};
183 | req.session['passport'] = {};
184 | req.session['passport'].user = '123456';
185 | })
186 | .authenticate();
187 | });
188 |
189 | it('should pass', function() {
190 | expect(pass).to.be.true;
191 | });
192 |
193 | it('should not set "user" on request', function() {
194 | expect(request.user).to.be.undefined;
195 | });
196 |
197 | it('should set "currentUser" on request', function() {
198 | expect(request.currentUser).to.be.an('object');
199 | expect(request.currentUser.id).to.equal('123456');
200 | });
201 | });
202 |
203 | describe('handling a request with a login session that encounters an error when deserializing', function() {
204 | var strategy = new SessionStrategy(function(user, req, done) {
205 | done(new Error('something went wrong'));
206 | });
207 |
208 | var request, error;
209 |
210 | before(function(done) {
211 | chai.passport.use(strategy)
212 | .error(function(err) {
213 | error = err;
214 | done();
215 | })
216 | .req(function(req) {
217 | request = req;
218 |
219 | req._passport = {};
220 | req._passport.instance = {};
221 | req.session = {};
222 | req.session['passport'] = {};
223 | req.session['passport'].user = '123456';
224 | })
225 | .authenticate();
226 | });
227 |
228 | it('should error', function() {
229 | expect(error).to.be.an.instanceOf(Error);
230 | expect(error.message).to.equal('something went wrong');
231 | });
232 |
233 | it('should not set user on request', function() {
234 | expect(request.user).to.be.undefined;
235 | });
236 |
237 | it('should maintain session', function() {
238 | expect(request.session['passport']).to.be.an('object');
239 | expect(request.session['passport'].user).to.equal('123456');
240 | });
241 | });
242 |
243 | describe('handling a request that lacks an authenticator', function() {
244 | var request, error;
245 |
246 | before(function(done) {
247 | chai.passport.use(strategy)
248 | .error(function(err) {
249 | error = err;
250 | done();
251 | })
252 | .req(function(req) {
253 | request = req;
254 | })
255 | .authenticate();
256 | });
257 |
258 | it('should error', function() {
259 | expect(error).to.be.an.instanceOf(Error);
260 | expect(error.message).to.equal('Login sessions require session support. Did you forget to use `express-session` middleware?');
261 | });
262 |
263 | it('should not set user on request', function() {
264 | expect(request.user).to.be.undefined;
265 | });
266 | });
267 |
268 | });
269 |
--------------------------------------------------------------------------------