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,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'
}
};