This commit is contained in:
2025-10-24 17:06:14 -05:00
parent 12d0690b91
commit df8c75603f
11289 changed files with 1209053 additions and 318 deletions

View File

@@ -0,0 +1,20 @@
name: Node.js CI
on: push
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [10.x, 11.x, 12.x, 13.x, 14.x, 15.x, 16.x, 17.x]
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}
- name: Install dependencies
run: npm ci
- run: npm run build --if-present
- run: npm test

11
qwen/nodejs/node_modules/passport-jwt/.travis.yml generated vendored Normal file
View File

@@ -0,0 +1,11 @@
language: node_js
node_js:
- "14"
- "13"
- "12"
- "11"
- "10"
- "9"
- "8"
- "7"
- "6"

22
qwen/nodejs/node_modules/passport-jwt/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2014 themikenicholson
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

169
qwen/nodejs/node_modules/passport-jwt/README.md generated vendored Normal file
View File

@@ -0,0 +1,169 @@
# passport-jwt
[![Build Status](https://travis-ci.org/mikenicholson/passport-jwt.svg?branch=master)](https://travis-ci.org/mikenicholson/passport-jwt)
[![Code Climate](https://codeclimate.com/github/mikenicholson/passport-jwt/badges/gpa.svg)](https://codeclimate.com/github/mikenicholson/passport-jwt)
A [Passport](http://passportjs.org/) strategy for authenticating with a
[JSON Web Token](http://jwt.io).
This module lets you authenticate endpoints using a JSON web token. It is
intended to be used to secure RESTful endpoints without sessions.
## Supported By
If you want to quickly add secure token-based authentication to Node.js apps, feel free to check out Auth0's Node.js SDK and free plan at [auth0.com/developers](https://auth0.com/developers?utm_source=GHsponsor&utm_medium=GHsponsor&utm_campaign=passport-jwt&utm_content=auth) <img alt='Auth0 Logo' src='https://s3.amazonaws.com/passport-jwt-img/Auth0+logo.svg'/>
## Install
npm install passport-jwt
## Usage
### Configure Strategy
The JWT authentication strategy is constructed as follows:
new JwtStrategy(options, verify)
`options` is an object literal containing options to control how the token is
extracted from the request or verified.
* `secretOrKey` is a string or buffer containing the secret
(symmetric) or PEM-encoded public key (asymmetric) for verifying the token's
signature. REQUIRED unless `secretOrKeyProvider` is provided.
* `secretOrKeyProvider` is a callback in the format `function secretOrKeyProvider(request, rawJwtToken, done)`,
which should call `done` with a secret or PEM-encoded public key (asymmetric) for the given key and request combination.
`done` accepts arguments in the format `function done(err, secret)`. Note it is up to the implementer to decode rawJwtToken.
REQUIRED unless `secretOrKey` is provided.
* `jwtFromRequest` (REQUIRED) Function that accepts a request as the only
parameter and returns either the JWT as a string or *null*. See
[Extracting the JWT from the request](#extracting-the-jwt-from-the-request) for
more details.
* `issuer`: If defined the token issuer (iss) will be verified against this
value.
* `audience`: If defined, the token audience (aud) will be verified against
this value.
* `algorithms`: List of strings with the names of the allowed algorithms. For instance, ["HS256", "HS384"].
* `ignoreExpiration`: if true do not validate the expiration of the token.
* `passReqToCallback`: If true the request will be passed to the verify
callback. i.e. verify(request, jwt_payload, done_callback).
* `jsonWebTokenOptions`: passport-jwt is verifying the token using [jsonwebtoken](https://github.com/auth0/node-jsonwebtoken).
Pass here an options object for any other option you can pass the jsonwebtoken verifier. (i.e maxAge)
`verify` is a function with the parameters `verify(jwt_payload, done)`
* `jwt_payload` is an object literal containing the decoded JWT payload.
* `done` is a passport error first callback accepting arguments
done(error, user, info)
An example configuration which reads the JWT from the http
Authorization header with the scheme 'bearer':
```js
var JwtStrategy = require('passport-jwt').Strategy,
ExtractJwt = require('passport-jwt').ExtractJwt;
var opts = {}
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
opts.secretOrKey = 'secret';
opts.issuer = 'accounts.examplesoft.com';
opts.audience = 'yoursite.net';
passport.use(new JwtStrategy(opts, function(jwt_payload, done) {
User.findOne({id: jwt_payload.sub}, function(err, user) {
if (err) {
return done(err, false);
}
if (user) {
return done(null, user);
} else {
return done(null, false);
// or you could create a new account
}
});
}));
```
### Extracting the JWT from the request
There are a number of ways the JWT may be included in a request. In order to remain as flexible as
possible the JWT is parsed from the request by a user-supplied callback passed in as the
`jwtFromRequest` parameter. This callback, from now on referred to as an extractor,
accepts a request object as an argument and returns the encoded JWT string or *null*.
#### Included extractors
A number of extractor factory functions are provided in passport-jwt.ExtractJwt. These factory
functions return a new extractor configured with the given parameters.
* ```fromHeader(header_name)``` creates a new extractor that looks for the JWT in the given http
header
* ```fromBodyField(field_name)``` creates a new extractor that looks for the JWT in the given body
field. You must have a body parser configured in order to use this method.
* ```fromUrlQueryParameter(param_name)``` creates a new extractor that looks for the JWT in the given
URL query parameter.
* ```fromAuthHeaderWithScheme(auth_scheme)``` creates a new extractor that looks for the JWT in the
authorization header, expecting the scheme to match auth_scheme.
* ```fromAuthHeaderAsBearerToken()``` creates a new extractor that looks for the JWT in the authorization header
with the scheme 'bearer'
* ```fromExtractors([array of extractor functions])``` creates a new extractor using an array of
extractors provided. Each extractor is attempted in order until one returns a token.
### Writing a custom extractor function
If the supplied extractors don't meet your needs you can easily provide your own callback. For
example, if you are using the cookie-parser middleware and want to extract the JWT in a cookie
you could use the following function as the argument to the jwtFromRequest option:
```js
var cookieExtractor = function(req) {
var token = null;
if (req && req.cookies) {
token = req.cookies['jwt'];
}
return token;
};
// ...
opts.jwtFromRequest = cookieExtractor;
```
### Authenticate requests
Use `passport.authenticate()` specifying `'JWT'` as the strategy.
```js
app.post('/profile', passport.authenticate('jwt', { session: false }),
function(req, res) {
res.send(req.user.profile);
}
);
```
### Include the JWT in requests
The method of including a JWT in a request depends entirely on the extractor
function you choose. For example, if you use the `fromAuthHeaderAsBearerToken`
extractor, you would include an `Authorization` header in your request with the
scheme set to `bearer`. e.g.
Authorization: bearer JSON_WEB_TOKEN_STRING.....
## Migrating
Read the [Migration Guide](docs/migrating.md) for help upgrading to the latest
major version of passport-jwt.
## Tests
npm install
npm test
To generate test-coverage reports:
npm install -g istanbul
npm run-script testcov
istanbul report
## License
The [MIT License](http://opensource.org/licenses/MIT)
Copyright (c) 2015 Mike Nicholson

View File

@@ -0,0 +1,70 @@
# Migration Guide
The following instructions should help in migrating to a new major version of
passport-jwt.
## Migrating from 3.x.x to 4.x.x
Version 4.0.0 was released to update [jsonwebtoken's](https://github.com/auth0/node-jsonwebtoken)
major version from v7 to v8 in order to fix a security issue (see
[#147](https://github.com/mikenicholson/passport-jwt/issues/147)).
Users of `passport-jwt` are exposed to the API of `jsonwebtoken` through the `jsonWebTokenOptions`
constructor option. Therefore, a major version rev of `jsonwebtoken` triggered a major version rev
of `passport-jwt`.
See the
[jsonwebtoken v7-v8 Migration Notes](https://github.com/auth0/node-jsonwebtoken/wiki/Migration-Notes:-v7-to-v8)
for the full details. The change in units for the `maxAge` attribute of `jsonWebTokenOptions` is
likely to impact the greatest number of `passport-jwt` users.
## Migrating from 2.x.x to 3.x.x
Version 3.0.0 removes the `ExtractJwt.fromAuthHeader()` extractor function that would extract
JWT's from `Authorization` headers with the auth scheme 'jwt'. The default authorization scheme
of 'jwt' as the was not RFC 6750 compliant. The extractor was replaced with
`ExtractJwt.fromAuthHeaderAsBearerToken()`. The removal of `ExtractJwt.fromAuthHeader()` was done
to clearly change the API so any code relying on the old API would clearly break, hopefully saving
people some debugging time.
If you want to maintain the behavior of `ExtractJwt.fromAuthHeader()` when switching to v3.3.0, simply
replace it with `ExtractJwt.fromAuthHeaderWithScheme('jwt')` in your implementation.
## Migrating from version 1.x.x to 2.x.x
The v2 API is not backwards compatible with v1, specifically with regards to the introduction
of the concept of JWT extractor functions. If you require the legacy behavior in v1 you can use
the extractor function ```versionOneCompatibility(options)```
*options* is an object with any of the three custom JWT extraction options present in the v1
constructor:
* `tokenBodyField`: Field in a request body to search for the JWT.
Default is auth_token.
* `tokenQueryParameterName`: Query parameter name containing the token.
Default is auth_token.
* `authScheme`: Expected authorization scheme if token is submitted through
the HTTP Authorization header. Defaults to JWT
If in v1 you constructed the strategy like this:
```js
var JwtStrategy = require('passport-jwt').Strategy;
var opts = {}
opts.tokenBodyField = 'MY_CUSTOM_BODY_FIELD';
opts.secretOrKey = 'secret';
opts.issuer = 'accounts.examplesoft.com';
opts.audience = 'yoursite.net';
passport.use(new JwtStrategy(opts, verifyFunction));
```
Identical behavior can be achieved under v2 with the versionOneCompatibility extractor:
```js
var JwtStrategy = require('passport-jwt').Strategy,
ExtractJwt = require('passport-jwt').ExtractJwt;
var opts = {}
opts.jwtFromRequest = ExtractJwt.versionOneCompatibility({ tokenBodyField = 'MY_CUSTOM_BODY_FIELD' });
opts.opts.secretOrKey = 'secret';
opts.issuer = 'accounts.examplesoft.com';
opts.audience = 'yoursite.net';
passport.use(new JwtStrategy(opts, verifyFunction));
```

View File

@@ -0,0 +1,19 @@
'use strict';
var re = /(\S+)\s+(\S+)/;
function parseAuthHeader(hdrValue) {
if (typeof hdrValue !== 'string') {
return null;
}
var matches = hdrValue.match(re);
return matches && { scheme: matches[1], value: matches[2] };
}
module.exports = {
parse: parseAuthHeader
};

View File

@@ -0,0 +1,134 @@
"use strict";
var url = require('url'),
auth_hdr = require('./auth_header');
// Note: express http converts all headers
// to lower case.
var AUTH_HEADER = "authorization",
LEGACY_AUTH_SCHEME = "JWT",
BEARER_AUTH_SCHEME = 'bearer';
var extractors = {};
extractors.fromHeader = function (header_name) {
return function (request) {
var token = null;
if (request.headers[header_name]) {
token = request.headers[header_name];
}
return token;
};
};
extractors.fromBodyField = function (field_name) {
return function (request) {
var token = null;
if (request.body && Object.prototype.hasOwnProperty.call(request.body, field_name)) {
token = request.body[field_name];
}
return token;
};
};
extractors.fromUrlQueryParameter = function (param_name) {
return function (request) {
var token = null,
parsed_url = url.parse(request.url, true);
if (parsed_url.query && Object.prototype.hasOwnProperty.call(parsed_url.query, param_name)) {
token = parsed_url.query[param_name];
}
return token;
};
};
extractors.fromAuthHeaderWithScheme = function (auth_scheme) {
var auth_scheme_lower = auth_scheme.toLowerCase();
return function (request) {
var token = null;
if (request.headers[AUTH_HEADER]) {
var auth_params = auth_hdr.parse(request.headers[AUTH_HEADER]);
if (auth_params && auth_scheme_lower === auth_params.scheme.toLowerCase()) {
token = auth_params.value;
}
}
return token;
};
};
extractors.fromAuthHeaderAsBearerToken = function () {
return extractors.fromAuthHeaderWithScheme(BEARER_AUTH_SCHEME);
};
extractors.fromExtractors = function(extractors) {
if (!Array.isArray(extractors)) {
throw new TypeError('extractors.fromExtractors expects an array')
}
return function (request) {
var token = null;
var index = 0;
while(!token && index < extractors.length) {
token = extractors[index].call(this, request);
index ++;
}
return token;
}
};
/**
* This extractor mimics the behavior of the v1.*.* extraction logic.
*
* This extractor exists only to provide an easy transition from the v1.*.* API to the v2.0.0
* API.
*
* This extractor first checks the auth header, if it doesn't find a token there then it checks the
* specified body field and finally the url query parameters.
*
* @param options
* authScheme: Expected scheme when JWT can be found in HTTP Authorize header. Default is JWT.
* tokenBodyField: Field in request body containing token. Default is auth_token.
* tokenQueryParameterName: Query parameter name containing the token. Default is auth_token.
*/
extractors.versionOneCompatibility = function (options) {
var authScheme = options.authScheme || LEGACY_AUTH_SCHEME,
bodyField = options.tokenBodyField || 'auth_token',
queryParam = options.tokenQueryParameterName || 'auth_token';
return function (request) {
var authHeaderExtractor = extractors.fromAuthHeaderWithScheme(authScheme);
var token = authHeaderExtractor(request);
if (!token) {
var bodyExtractor = extractors.fromBodyField(bodyField);
token = bodyExtractor(request);
}
if (!token) {
var queryExtractor = extractors.fromUrlQueryParameter(queryParam);
token = queryExtractor(request);
}
return token;
};
}
/**
* Export the Jwt extraction functions
*/
module.exports = extractors;

View File

@@ -0,0 +1,24 @@
// note: This is a polyfill to Object.assign to support old nodejs versions (0.10 / 0.12) where
// Object.assign doesn't exist.
// Source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
module.exports = function(target, varArgs) {
if (target == null) { // TypeError if undefined or null
throw new TypeError('Cannot convert undefined or null to object');
}
var to = Object(target);
for (var index = 1; index < arguments.length; index++) {
var nextSource = arguments[index];
if (nextSource != null) { // Skip over if undefined or null
for (var nextKey in nextSource) {
// Avoid bugs when hasOwnProperty is shadowed
if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
to[nextKey] = nextSource[nextKey];
}
}
}
}
return to;
};

10
qwen/nodejs/node_modules/passport-jwt/lib/index.js generated vendored Normal file
View File

@@ -0,0 +1,10 @@
'use strict';
var Strategy = require('./strategy'),
ExtractJwt = require('./extract_jwt.js');
module.exports = {
Strategy: Strategy,
ExtractJwt : ExtractJwt
};

139
qwen/nodejs/node_modules/passport-jwt/lib/strategy.js generated vendored Normal file
View File

@@ -0,0 +1,139 @@
var passport = require('passport-strategy')
, auth_hdr = require('./auth_header')
, util = require('util')
, url = require('url')
, assign = require('./helpers/assign.js');
/**
* Strategy constructor
*
* @param options
* secretOrKey: String or buffer containing the secret or PEM-encoded public key. Required unless secretOrKeyProvider is provided.
* secretOrKeyProvider: callback in the format secretOrKeyProvider(request, rawJwtToken, done)`,
* which should call done with a secret or PEM-encoded public key
* (asymmetric) for the given undecoded jwt token string and request
* combination. done has the signature function done(err, secret).
* REQUIRED unless `secretOrKey` is provided.
* jwtFromRequest: (REQUIRED) Function that accepts a request as the only parameter and returns the either JWT as a string or null
* issuer: If defined issuer will be verified against this value
* audience: If defined audience will be verified against this value
* algorithms: List of strings with the names of the allowed algorithms. For instance, ["HS256", "HS384"].
* ignoreExpiration: if true do not validate the expiration of the token.
* passReqToCallback: If true the verify callback will be called with args (request, jwt_payload, done_callback).
* @param verify - Verify callback with args (jwt_payload, done_callback) if passReqToCallback is false,
* (request, jwt_payload, done_callback) if true.
*/
function JwtStrategy(options, verify) {
passport.Strategy.call(this);
this.name = 'jwt';
this._secretOrKeyProvider = options.secretOrKeyProvider;
if (options.secretOrKey) {
if (this._secretOrKeyProvider) {
throw new TypeError('JwtStrategy has been given both a secretOrKey and a secretOrKeyProvider');
}
this._secretOrKeyProvider = function (request, rawJwtToken, done) {
done(null, options.secretOrKey)
};
}
if (!this._secretOrKeyProvider) {
throw new TypeError('JwtStrategy requires a secret or key');
}
this._verify = verify;
if (!this._verify) {
throw new TypeError('JwtStrategy requires a verify callback');
}
this._jwtFromRequest = options.jwtFromRequest;
if (!this._jwtFromRequest) {
throw new TypeError('JwtStrategy requires a function to retrieve jwt from requests (see option jwtFromRequest)');
}
this._passReqToCallback = options.passReqToCallback;
var jsonWebTokenOptions = options.jsonWebTokenOptions || {};
//for backwards compatibility, still allowing you to pass
//audience / issuer / algorithms / ignoreExpiration
//on the options.
this._verifOpts = assign({}, jsonWebTokenOptions, {
audience: options.audience,
issuer: options.issuer,
algorithms: options.algorithms,
ignoreExpiration: !!options.ignoreExpiration
});
}
util.inherits(JwtStrategy, passport.Strategy);
/**
* Allow for injection of JWT Verifier.
*
* This improves testability by allowing tests to cleanly isolate failures in the JWT Verification
* process from failures in the passport related mechanics of authentication.
*
* Note that this should only be replaced in tests.
*/
JwtStrategy.JwtVerifier = require('./verify_jwt');
/**
* Authenticate request based on JWT obtained from header or post body
*/
JwtStrategy.prototype.authenticate = function(req, options) {
var self = this;
var token = self._jwtFromRequest(req);
if (!token) {
return self.fail(new Error("No auth token"));
}
this._secretOrKeyProvider(req, token, function(secretOrKeyError, secretOrKey) {
if (secretOrKeyError) {
self.fail(secretOrKeyError)
} else {
// Verify the JWT
JwtStrategy.JwtVerifier(token, secretOrKey, self._verifOpts, function(jwt_err, payload) {
if (jwt_err) {
return self.fail(jwt_err);
} else {
// Pass the parsed token to the user
var verified = function(err, user, info) {
if(err) {
return self.error(err);
} else if (!user) {
return self.fail(info);
} else {
return self.success(user, info);
}
};
try {
if (self._passReqToCallback) {
self._verify(req, payload, verified);
} else {
self._verify(payload, verified);
}
} catch(ex) {
self.error(ex);
}
}
});
}
});
};
/**
* Export the Jwt Strategy
*/
module.exports = JwtStrategy;

View File

@@ -0,0 +1,5 @@
var jwt = require('jsonwebtoken');
module.exports = function(token, secretOrKey, options, callback) {
return jwt.verify(token, secretOrKey, options, callback);
};

39
qwen/nodejs/node_modules/passport-jwt/package.json generated vendored Normal file
View File

@@ -0,0 +1,39 @@
{
"name": "passport-jwt",
"version": "4.0.1",
"description": "Passport authentication strategy using JSON Web Tokens",
"main": "./lib",
"scripts": {
"test": "./node_modules/.bin/mocha --reporter spec --require test/bootstrap test/*test.js",
"testcov": "nyc npm run test"
},
"repository": {
"type": "git",
"url": "https://github.com/mikenicholson/passport-jwt.git"
},
"keywords": [
"Passport",
"Strategy",
"JSON",
"Web",
"Token",
"JWT"
],
"author": "Mike Nicholson",
"license": "MIT",
"bugs": {
"url": "https://github.com/mikenicholson/passport-jwt/issues"
},
"homepage": "https://github.com/mikenicholson/passport-jwt",
"devDependencies": {
"chai": "^3.0.0",
"chai-passport-strategy": "^1.0.0",
"mocha": "^9.2.1",
"nyc": "^15.1.0",
"sinon": "^1.0.0"
},
"dependencies": {
"jsonwebtoken": "^9.0.0",
"passport-strategy": "^1.0.0"
}
}

View File

@@ -0,0 +1,28 @@
var auth_hdr = require('../lib/auth_header')
describe('Parsing Auth Header field-value', function() {
it('Should handle single space separated values', function() {
var res = auth_hdr.parse("SCHEME VALUE");
expect(res).to.deep.equal({scheme: "SCHEME", value: "VALUE"});
});
it('Should handle CRLF separator', function() {
var res = auth_hdr.parse("SCHEME\nVALUE");
expect(res).to.deep.equal({scheme: "SCHEME", value: "VALUE"});
});
it('Should handle malformed authentication headers with no scheme', function() {
var res = auth_hdr.parse("malformed");
expect(res).to.not.be.ok;
});
it('Should return null when the auth header is not a string', function() {
var res = auth_hdr.parse({});
expect(res).to.be.null;
});
});

View File

@@ -0,0 +1,3 @@
var chai = require('chai');
chai.use(require('chai-passport-strategy'));
global.expect = chai.expect;

View File

@@ -0,0 +1,287 @@
var extract_jwt = require('../lib/extract_jwt'),
Request = require('./mock_request');
describe('Token extractor', function() {
describe('fromHeader', function() {
var extractor = extract_jwt.fromHeader('test_header');
it('should return null no when token is present', function() {
var req = new Request();
var token = extractor(req);
expect(token).to.be.null;
});
it('should return the value from the specified header', function() {
var req = new Request();
req.headers['test_header'] = 'abcd123'
var token = extractor(req)
expect(token).to.equal('abcd123');
});
});
describe('fromBodyField', function() {
var extractor = extract_jwt.fromBodyField('test_field');
it('should return null when no body is present', function() {
var req = new Request();
var token = extractor(req);
expect(token).to.be.null;
});
it('should return null when the specified body field is not present', function() {
var req = new Request();
req.body = {};
var token = extractor(req);
expect(token).to.be.null;
});
it('should return the value from the specified body field', function() {
var req = new Request();
req.body = {};
req.body.test_field = 'abcd123';
var token = extractor(req);
expect(token).to.equal('abcd123');
});
it('should work properly with querystring', function() {
var req = new Request();
const querystring = require('querystring');
req.body = querystring.parse('test_field=abcd123')
var token = extractor(req);
expect(token).to.equal('abcd123')
});
});
describe('fromUrlQueryParameter', function() {
var extractor = extract_jwt.fromUrlQueryParameter('test_param');
it('should return null when the specified paramter is not present', function() {
var req = new Request();
var token = extractor(req);
expect(token).to.be.null;
});
it('should return the value from the specified parameter', function() {
var req = new Request();
req.url += '?test_param=abcd123';
var token = extractor(req);
expect(token).to.equal('abcd123');
});
});
describe('fromAuthHeaderWithScheme', function() {
var extractor = extract_jwt.fromAuthHeaderWithScheme('TEST_SCHEME');
it('should return null when no auth header is present', function() {
var req = new Request();
var token = extractor(req);
expect(token).to.be.null;
});
it('should return null when the auth header is present but the auth scheme doesnt match', function() {
var req = new Request()
req.headers['authorization'] = "NOT_TEST_SCHEME abcd123";
var token = extractor(req);
expect(token).to.be.null;
});
it('should return the value from the authorization header with specified auth scheme', function() {
var req = new Request()
req.headers['authorization'] = "TEST_SCHEME abcd123";
var token = extractor(req);
expect(token).to.equal('abcd123');
});
it('should perform a case-insensivite string comparison', function () {
var req = new Request()
req.headers['authorization'] = 'test_scheme abcd123';
var token = extractor(req);
expect(token).to.equal('abcd123');
});
});
describe('fromAuthHeader', function() {
var extractor = extract_jwt.fromAuthHeaderAsBearerToken();
it('should return the value from the authorization header with default JWT auth scheme', function() {
var req = new Request()
req.headers['authorization'] = "bearer abcd123";
var token = extractor(req);
expect(token).to.equal('abcd123');
});
});
describe('fromExtractors', function() {
it('should raise a type error when the extractor is constructed with a non-array argument', function() {
this_should_throw = function() {
var extractor = extract_jwt.fromExtractors({})
}
expect(this_should_throw).to.throw(TypeError)
});
var extractor = extract_jwt.fromExtractors([extract_jwt.fromAuthHeaderAsBearerToken(), extract_jwt.fromHeader('authorization')]);
it('should return null when no extractor extracts token', function() {
var req = new Request();
var token = extractor(req);
expect(token).to.be.null;
});
it('should return token found by least extractor', function() {
var req = new Request()
req.headers['authorization'] = "abcd123";
var token = extractor(req);
expect(token).to.equal('abcd123');
});
it('should return token found by first extractor', function() {
var req = new Request()
req.headers['authorization'] = "bearer abcd123";
var token = extractor(req);
expect(token).to.equal('abcd123');
});
});
describe('versionOneCompatibility', function () {
describe('default behavior', function() {
var extractor = extract_jwt.versionOneCompatibility({});
it('should return the token in the default "JWT" auth header', function () {
var req = new Request();
req.headers['authorization'] = "JWT abcd123";
var token = extractor(req);
expect(token).to.equal('abcd123');
});
it('should return the token in the default "auth_token" body field', function () {
var req = new Request();
req.body = {};
req.body['auth_token'] = 'xyzabcd';
var token = extractor(req);
expect(token).to.equal('xyzabcd');
});
it('should return then token in the default "auth_token" query parameter', function () {
var req = new Request();
req.url += '?auth_token=abcd123';
var token = extractor(req);
expect(token).to.equal('abcd123');
});
});
describe('user supplied parameters', function() {
it('should return the token in an auth header with a user specified auth scheme', function() {
var opts = { authScheme: 'MY_CUSTOM_AUTH_SCHEME' };
var extractor = extract_jwt.versionOneCompatibility(opts);
var req = new Request();
req.headers['authorization'] = 'MY_CUSTOM_AUTH_SCHEME deadbeef';
var token = extractor(req);
expect(token).to.equal('deadbeef');
});
it('should return the token in a user supplied body field', function () {
var opts = { tokenBodyField: 'CUSTOM_BODY_FIELD' };
var extractor = extract_jwt.versionOneCompatibility(opts);
var req = new Request();
req.body = {};
req.body['CUSTOM_BODY_FIELD'] = 'badbeef';
var token = extractor(req);
expect(token).to.equal('badbeef');
});
it('should return the token in a user specified query parameter', function () {
var opts = { tokenQueryParameterName: 'CustomQueryParam' };
var extractor = extract_jwt.versionOneCompatibility(opts);
var req = new Request();
req.url += '?CustomQueryParam=deadbeef';
var token = extractor(req);
expect(token).to.equal('deadbeef');
});
});
});
});

View File

@@ -0,0 +1,10 @@
/**
A mock Request for testing jwt extractor functions
*/
function Request() {
this.method = 'GET';
this.url = '/';
this.headers = {};
}
module.exports = Request;

View File

@@ -0,0 +1,41 @@
var Strategy = require('../lib/strategy');
describe('Strategy', function() {
var strategy = new Strategy({jwtFromRequest: function(){}, secretOrKey: 'secret'}, function() {});
it('should be named jwt', function() {
expect(strategy.name).to.equal('jwt');
});
it('should throw if constructed without a verify callback', function() {
expect(function() {
var s = new Strategy({jwtFromRequest: function(r) {}, secretOrKey: 'secret'});
}).to.throw(TypeError, "JwtStrategy requires a verify callback");
});
it('should throw if constructed neither a secretOrKey or a secretOrKeyProvider arg', function() {
expect(function() {
var s = new Strategy({jwtFromRequest: function(r) {}, secretOrKey: null}, function() {});
}).to.throw(TypeError, 'JwtStrategy requires a secret or key');
});
it('should throw if constructed with both a secretOrKey and a secretOrKeyProvider', function () {
expect(function() {
var s = new Strategy({
secretOrKey: 'secret',
secretOrKeyProvider: function(req, token, done) {},
jwtFromRequest: function(r) {}
});
}).to.throw(TypeError);
});
it('should throw if constructed without a jwtFromRequest arg', function() {
expect(function() {
var s = new Strategy({secretOrKey: 'secret'}, function() {});
}).to.throw(TypeError);
});
});

View File

@@ -0,0 +1,124 @@
var Strategy = require('../lib/strategy')
, chai = require('chai')
, sinon = require('sinon')
, test_data= require('./testdata')
, url = require('url')
, extract_jwt = require('../lib/extract_jwt')
describe('Strategy', function() {
var mockVerifier = null;
before(function() {
// Replace the JWT Verfier with a stub to capture the value
// extracted from the request
mockVerifier = sinon.stub();
mockVerifier.callsArgWith(3, null, test_data.valid_jwt.payload);
Strategy.JwtVerifier = mockVerifier;
});
describe('handling request JWT present in request', function() {
var strategy;
before(function(done) {
strategy = new Strategy({
jwtFromRequest: function (r) { return test_data.valid_jwt.token; },
secretOrKey: 'secret'
},
function(jwt_payload, next) {
// Return values aren't important in this case
return next(null, {}, {});
}
);
mockVerifier.reset();
chai.passport.use(strategy)
.success(function(u, i) {
done();
})
.authenticate();
});
it("verifies the right jwt", function() {
sinon.assert.calledOnce(mockVerifier);
expect(mockVerifier.args[0][0]).to.equal(test_data.valid_jwt.token);
});
});
describe('handling request with NO JWT', function() {
var info;
before(function(done) {
strategy = new Strategy({jwtFromRequest: function(r) {}, secretOrKey: 'secret'}, function(jwt_payload, next) {
// Return values aren't important in this case
return next(null, {}, {});
});
mockVerifier.reset();
chai.passport.use(strategy)
.fail(function(i) {
info = i
done();
})
.req(function(req) {
req.body = {}
})
.authenticate();
});
it('should fail authentication', function() {
expect(info).to.be.an.object;
expect(info.message).to.equal("No auth token");
});
it('Should not try to verify anything', function() {
sinon.assert.notCalled(mockVerifier);
});
});
describe('handling request url set to url.Url instead of string', function() {
var info;
before(function(done) {
strategy = new Strategy({jwtFromRequest: function(r) {}, secretOrKey: 'secret'}, function(jwt_payload, next) {
// Return values aren't important in this case
return next(null, {}, {});
});
mockVerifier.reset();
chai.passport.use(strategy)
.fail(function(i) {
info = i
done();
})
.req(function(req) {
req.body = {};
req.url = new url.Url('/');
})
.authenticate();
});
it('should fail authentication', function() {
expect(info).to.be.an.object;
expect(info.message).to.equal("No auth token");
});
});
});

View File

@@ -0,0 +1,182 @@
var Strategy = require('../lib/strategy')
, chai = require('chai')
, test_data = require('./testdata')
, sinon = require('sinon')
, extract_jwt = require('../lib/extract_jwt');
describe('Strategy', function() {
describe('calling JWT validation function', function() {
var strategy;
before(function(done) {
verifyStub = sinon.stub();
verifyStub.callsArgWith(1, null, {}, {});
options = {};
options.issuer = "TestIssuer";
options.audience = "TestAudience";
options.secretOrKey = 'secret';
options.algorithms = ["HS256", "HS384"];
options.ignoreExpiration = false;
options.jsonWebTokenOptions = {
clockTolerance: 10,
maxAge: "1h",
};
options.jwtFromRequest = extract_jwt.fromAuthHeaderAsBearerToken();
strategy = new Strategy(options, verifyStub);
Strategy.JwtVerifier = sinon.stub();
Strategy.JwtVerifier.callsArgWith(3, null, test_data.valid_jwt.payload);
chai.passport.use(strategy)
.success(function(u, i) {
done();
})
.req(function(req) {
req.headers['authorization'] = "bearer " + test_data.valid_jwt.token;
})
.authenticate();
});
it('should call with the right secret as an argument', function() {
expect(Strategy.JwtVerifier.args[0][1]).to.equal('secret');
});
it('should call with the right issuer option', function() {
expect(Strategy.JwtVerifier.args[0][2]).to.be.an.object;
expect(Strategy.JwtVerifier.args[0][2].issuer).to.equal('TestIssuer');
});
it('should call with the right audience option', function() {
expect(Strategy.JwtVerifier.args[0][2]).to.be.an.object;
expect(Strategy.JwtVerifier.args[0][2].audience).to.equal('TestAudience');
});
it('should call with the right algorithms option', function() {
expect(Strategy.JwtVerifier.args[0][2]).to.be.an.object;
expect(Strategy.JwtVerifier.args[0][2].algorithms).to.eql(["HS256", "HS384"]);
});
it('should call with the right ignoreExpiration option', function() {
expect(Strategy.JwtVerifier.args[0][2]).to.be.an.object;
expect(Strategy.JwtVerifier.args[0][2].ignoreExpiration).to.be.false;
});
it('should call with the right maxAge option', function() {
expect(Strategy.JwtVerifier.args[0][2]).to.be.an.object;
expect(Strategy.JwtVerifier.args[0][2].maxAge).to.equal('1h');
});
it('should call with the right clockTolerance option', function() {
expect(Strategy.JwtVerifier.args[0][2]).to.be.an.object;
expect(Strategy.JwtVerifier.args[0][2].clockTolerance).to.equal(10);
});
});
describe('handling valid jwt', function() {
var strategy, payload;
before(function(done) {
strategy = new Strategy({jwtFromRequest: extract_jwt.fromAuthHeaderAsBearerToken(), secretOrKey: 'secret'}, function(jwt_payload, next) {
payload = jwt_payload;
next(null, {}, {});
});
// Mock successful verification
Strategy.JwtVerifier = sinon.stub();
Strategy.JwtVerifier.callsArgWith(3, null, test_data.valid_jwt.payload);
chai.passport.use(strategy)
.success(function(u, i) {
done();
})
.req(function(req) {
req.headers['authorization'] = "bearer " + test_data.valid_jwt.token;
})
.authenticate();
});
it('should call verify with the correct payload', function() {
expect(payload).to.deep.equal(test_data.valid_jwt.payload);
});
});
describe('handling failing jwt', function() {
var strategy, info;
var verify_spy = sinon.spy();
before(function(done) {
strategy = new Strategy({jwtFromRequest: extract_jwt.fromAuthHeaderAsBearerToken(), secretOrKey: 'secret'}, verify_spy);
// Mock errored verification
Strategy.JwtVerifier = sinon.stub();
Strategy.JwtVerifier.callsArgWith(3, new Error("jwt expired"), false);
chai.passport.use(strategy)
.fail(function(i) {
info = i;
done();
})
.req(function(req) {
req.headers['authorization'] = "bearer " + test_data.valid_jwt.token;
})
.authenticate();
});
it('should not call verify', function() {
sinon.assert.notCalled(verify_spy);
});
it('should fail with error message.', function() {
expect(info).to.be.an.object;
expect(info.message).to.equal('jwt expired');
});
});
describe('handling an invalid authentication header', function() {
var strategy, info;
var verify_spy = sinon.spy();
before(function(done) {
strategy = new Strategy({jwtFromRequest: extract_jwt.fromAuthHeaderAsBearerToken(), secretOrKey: 'secret'}, verify_spy);
chai.passport.use(strategy)
.fail(function(i) {
info = i;
done();
})
.req(function(req) {
req.headers['authorization'] = "malformed";
})
.authenticate();
});
it('should not call verify', function() {
sinon.assert.notCalled(verify_spy);
});
it('should fail with error message.', function() {
expect(info).to.be.an.object;
expect(info).to.be.an.instanceof(Error);
});
});
});

View File

@@ -0,0 +1,245 @@
var chai = require('chai')
, Strategy = require('../lib/strategy')
, test_data = require('./testdata')
, sinon = require('sinon')
, verify = require('../lib/verify_jwt')
, extract_jwt = require('../lib/extract_jwt');
describe('Strategy', function() {
before(function() {
Strategy.JwtVerifier = sinon.stub();
Strategy.JwtVerifier.callsArgWith(3, null, test_data.valid_jwt.payload);
});
describe('Handling a request with a valid JWT and succesful verification', function() {
var strategy, user, info;
before(function(done) {
strategy = new Strategy({jwtFromRequest:extract_jwt.fromAuthHeaderAsBearerToken(), secretOrKey: 'secret'}, function(jwt_paylod, next) {
return next(null, {user_id: 1234567890}, {foo:'bar'});
});
chai.passport.use(strategy)
.success(function(u, i) {
user = u;
info = i;
done();
})
.req(function(req) {
req.headers['authorization'] = "bearer " + test_data.valid_jwt.token;
})
.authenticate();
});
it('should provide a user', function() {
expect(user).to.be.an.object;
expect(user.user_id).to.equal(1234567890);
});
it('should forward info', function() {
expect(info).to.be.an.object;
expect(info.foo).to.equal('bar');
});
});
describe('handling a request with valid jwt and failed verification', function() {
var strategy, info;
before(function(done) {
strategy = new Strategy({jwtFromRequest: extract_jwt.fromAuthHeaderAsBearerToken(), secretOrKey: 'secret'}, function(jwt_payload, next) {
return next(null, false, {message: 'invalid user'});
});
chai.passport.use(strategy)
.fail(function(i) {
info = i;
done();
})
.req(function(req) {
req.headers['authorization'] = "bearer " + test_data.valid_jwt.token;
})
.authenticate();
});
it('should fail with info', function() {
expect(info).to.be.an.object;
expect(info.message).to.equal('invalid user');
});
});
describe('handling a request with a valid jwt and an error during verification', function() {
var strategy, err;
before(function(done) {
strategy = new Strategy({jwtFromRequest: extract_jwt.fromAuthHeaderAsBearerToken(), secretOrKey: 'secrety'}, function(jwt_payload, next) {
return next(new Error("ERROR"), false, {message: 'invalid user'});
});
chai.passport.use(strategy)
.error(function(e) {
err = e;
done();
})
.req(function(req) {
req.headers['authorization'] = "bearer " + test_data.valid_jwt.token;
})
.authenticate();
});
it('should error', function() {
expect(err).to.be.an.instanceof(Error);
expect(err.message).to.equal('ERROR');
});
});
describe('handling a request with a valid jwt and an exception during verification', function() {
var strategy, err;
before(function(done) {
strategy = new Strategy({jwtFromRequest: extract_jwt.fromAuthHeaderAsBearerToken(), secretOrKey: 'secret'}, function(jwt_payload, next) {
throw new Error("EXCEPTION");
});
chai.passport.use(strategy)
.error(function(e) {
err = e;
done();
})
.req(function(req) {
req.headers['authorization'] = "bearer " + test_data.valid_jwt.token;
})
.authenticate();
});
it('should error', function() {
expect(err).to.be.an.instanceof(Error);
expect(err.message).to.equal('EXCEPTION');
});
});
describe('handling a request with a valid jwt and option passReqToCallback is true', function() {
var strategy, expected_request, request_arg;
before(function(done) {
opts = { passReqToCallback: true };
opts.secretOrKey = 'secret';
opts.jwtFromRequest = extract_jwt.fromAuthHeaderAsBearerToken();
strategy = new Strategy(opts, function(request, jwt_payload, next) {
// Capture the value passed in as the request argument
request_arg = request;
return next(null, {user_id: 1234567890}, {foo:'bar'});
});
chai.passport.use(strategy)
.success(function(u, i) {
done();
})
.req(function(req) {
req.headers['authorization'] = "bearer " + test_data.valid_jwt.token;
expected_request = req;
})
.authenticate();
});
it('will call verify with request as the first argument', function() {
expect(expected_request).to.equal(request_arg);
});
});
describe('handling a request when constructed with a secretOrKeyProvider function that succeeds', function() {
var strategy, fakeSecretOrKeyProvider, expectedReqeust;
before(function(done) {
fakeSecretOrKeyProvider = sinon.spy(function(request, token, done) {
done(null, 'secret from callback');
});
opts = {
secretOrKeyProvider: fakeSecretOrKeyProvider,
jwtFromRequest: function(request) {
return 'an undecoded jwt string';
}
}
strategy = new Strategy(opts, function(jwtPayload, next) {
return next(null, {user_id: 'dont care'}, {});
});
chai.passport.use(strategy)
.success(function(u, i) {
done();
})
.req(function(req) {
expectedReqeust = req;
})
.authenticate();
});
it('should call the fake secret or key provider with the reqeust', function() {
expect(fakeSecretOrKeyProvider.calledWith(expectedReqeust, sinon.match.any, sinon.match.any)).to.be.true;
});
it('should call the secretOrKeyProvider with the undecoded jwt', function() {
expect(fakeSecretOrKeyProvider.calledWith(sinon.match.any, 'an undecoded jwt string', sinon.match.any)).to.be.true;
});
it('should call JwtVerifier with the value returned from secretOrKeyProvider', function() {
expect(Strategy.JwtVerifier.calledWith(sinon.match.any, 'secret from callback', sinon.match.any, sinon.match.any)).to.be.true;
});
});
describe('handling a request when constructed with a secretOrKeyProvider function that errors', function() {
var errorMessage;
before(function(done) {
fakeSecretOrKeyProvider = sinon.spy(function(request, token, done) {
done('Error occurred looking for the secret');
});
opts = {
secretOrKeyProvider: fakeSecretOrKeyProvider,
jwtFromRequest: function(request) {
return 'an undecoded jwt string';
}
}
strategy = new Strategy(opts, function(jwtPayload, next) {
return next(null, {user_id: 'dont care'}, {});
});
chai.passport.use(strategy)
.fail(function(i) {
errorMessage = i;
done();
})
.authenticate();
});
it('should fail with the error message from the secretOrKeyProvider', function() {
expect(errorMessage).to.equal('Error occurred looking for the secret');
});
});
});

14
qwen/nodejs/node_modules/passport-jwt/test/testdata.js generated vendored Normal file
View File

@@ -0,0 +1,14 @@
module.exports = {
// Note, this JWT will expire sometime in 2286. If unit tests are failing around this time try
// generating a new, valid token :)
valid_jwt : {
token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOjEyMzQ1Njc4OTAsIm5hbWUiOiJKb2huIERvZSIsImlzcyI6ImV4YW1wbGVzb2Z0LmNvbSIsImV4cCI6Ijk5OTk5OTk5OTkifQ.CbpI0TNI-FYXe6p3PgM__jwlz6aCT1qpUBsTVCfWuBM",
payload : {
"sub": "1234567890",
"name": "John Doe",
"iss": "examplesoft.com",
"exp": "9999999999"
},
secret: 'secret'
}
};