passport-jwt-v2 4.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/ci.yml +20 -0
- package/.travis.yml +11 -0
- package/LICENSE +22 -0
- package/README.md +169 -0
- package/docs/migrating.md +70 -0
- package/lib/auth_header.js +19 -0
- package/lib/extract_jwt.js +134 -0
- package/lib/helpers/assign.js +24 -0
- package/lib/index.js +10 -0
- package/lib/strategy.js +139 -0
- package/lib/verify_jwt.js +5 -0
- package/package.json +44 -0
- package/test/auth_header-test.js +28 -0
- package/test/bootstrap.js +3 -0
- package/test/extractors-test.js +287 -0
- package/test/mock_request.js +10 -0
- package/test/strategy-init-test.js +41 -0
- package/test/strategy-requests-test.js +124 -0
- package/test/strategy-validation-test.js +182 -0
- package/test/strategy-verify-test.js +245 -0
- package/test/testdata.js +14 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
var auth_hdr = require('../lib/auth_header')
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
describe('Parsing Auth Header field-value', function() {
|
|
5
|
+
|
|
6
|
+
it('Should handle single space separated values', function() {
|
|
7
|
+
var res = auth_hdr.parse("SCHEME VALUE");
|
|
8
|
+
expect(res).to.deep.equal({scheme: "SCHEME", value: "VALUE"});
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
it('Should handle CRLF separator', function() {
|
|
13
|
+
var res = auth_hdr.parse("SCHEME\nVALUE");
|
|
14
|
+
expect(res).to.deep.equal({scheme: "SCHEME", value: "VALUE"});
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
it('Should handle malformed authentication headers with no scheme', function() {
|
|
19
|
+
var res = auth_hdr.parse("malformed");
|
|
20
|
+
expect(res).to.not.be.ok;
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
it('Should return null when the auth header is not a string', function() {
|
|
25
|
+
var res = auth_hdr.parse({});
|
|
26
|
+
expect(res).to.be.null;
|
|
27
|
+
});
|
|
28
|
+
});
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
var extract_jwt = require('../lib/extract_jwt'),
|
|
2
|
+
Request = require('./mock_request');
|
|
3
|
+
|
|
4
|
+
describe('Token extractor', function() {
|
|
5
|
+
|
|
6
|
+
describe('fromHeader', function() {
|
|
7
|
+
|
|
8
|
+
var extractor = extract_jwt.fromHeader('test_header');
|
|
9
|
+
|
|
10
|
+
it('should return null no when token is present', function() {
|
|
11
|
+
var req = new Request();
|
|
12
|
+
|
|
13
|
+
var token = extractor(req);
|
|
14
|
+
|
|
15
|
+
expect(token).to.be.null;
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
it('should return the value from the specified header', function() {
|
|
20
|
+
var req = new Request();
|
|
21
|
+
req.headers['test_header'] = 'abcd123'
|
|
22
|
+
|
|
23
|
+
var token = extractor(req)
|
|
24
|
+
|
|
25
|
+
expect(token).to.equal('abcd123');
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
describe('fromBodyField', function() {
|
|
31
|
+
|
|
32
|
+
var extractor = extract_jwt.fromBodyField('test_field');
|
|
33
|
+
|
|
34
|
+
it('should return null when no body is present', function() {
|
|
35
|
+
var req = new Request();
|
|
36
|
+
|
|
37
|
+
var token = extractor(req);
|
|
38
|
+
|
|
39
|
+
expect(token).to.be.null;
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
it('should return null when the specified body field is not present', function() {
|
|
44
|
+
var req = new Request();
|
|
45
|
+
req.body = {};
|
|
46
|
+
|
|
47
|
+
var token = extractor(req);
|
|
48
|
+
|
|
49
|
+
expect(token).to.be.null;
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
it('should return the value from the specified body field', function() {
|
|
54
|
+
var req = new Request();
|
|
55
|
+
req.body = {};
|
|
56
|
+
req.body.test_field = 'abcd123';
|
|
57
|
+
|
|
58
|
+
var token = extractor(req);
|
|
59
|
+
|
|
60
|
+
expect(token).to.equal('abcd123');
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
it('should work properly with querystring', function() {
|
|
65
|
+
var req = new Request();
|
|
66
|
+
const querystring = require('querystring');
|
|
67
|
+
req.body = querystring.parse('test_field=abcd123')
|
|
68
|
+
|
|
69
|
+
var token = extractor(req);
|
|
70
|
+
|
|
71
|
+
expect(token).to.equal('abcd123')
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
describe('fromUrlQueryParameter', function() {
|
|
77
|
+
|
|
78
|
+
var extractor = extract_jwt.fromUrlQueryParameter('test_param');
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
it('should return null when the specified paramter is not present', function() {
|
|
82
|
+
var req = new Request();
|
|
83
|
+
|
|
84
|
+
var token = extractor(req);
|
|
85
|
+
|
|
86
|
+
expect(token).to.be.null;
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
it('should return the value from the specified parameter', function() {
|
|
91
|
+
var req = new Request();
|
|
92
|
+
req.url += '?test_param=abcd123';
|
|
93
|
+
|
|
94
|
+
var token = extractor(req);
|
|
95
|
+
|
|
96
|
+
expect(token).to.equal('abcd123');
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
describe('fromAuthHeaderWithScheme', function() {
|
|
102
|
+
|
|
103
|
+
var extractor = extract_jwt.fromAuthHeaderWithScheme('TEST_SCHEME');
|
|
104
|
+
|
|
105
|
+
it('should return null when no auth header is present', function() {
|
|
106
|
+
var req = new Request();
|
|
107
|
+
|
|
108
|
+
var token = extractor(req);
|
|
109
|
+
|
|
110
|
+
expect(token).to.be.null;
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
it('should return null when the auth header is present but the auth scheme doesnt match', function() {
|
|
115
|
+
var req = new Request()
|
|
116
|
+
req.headers['authorization'] = "NOT_TEST_SCHEME abcd123";
|
|
117
|
+
|
|
118
|
+
var token = extractor(req);
|
|
119
|
+
|
|
120
|
+
expect(token).to.be.null;
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
it('should return the value from the authorization header with specified auth scheme', function() {
|
|
125
|
+
var req = new Request()
|
|
126
|
+
req.headers['authorization'] = "TEST_SCHEME abcd123";
|
|
127
|
+
|
|
128
|
+
var token = extractor(req);
|
|
129
|
+
|
|
130
|
+
expect(token).to.equal('abcd123');
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
it('should perform a case-insensivite string comparison', function () {
|
|
135
|
+
var req = new Request()
|
|
136
|
+
req.headers['authorization'] = 'test_scheme abcd123';
|
|
137
|
+
|
|
138
|
+
var token = extractor(req);
|
|
139
|
+
|
|
140
|
+
expect(token).to.equal('abcd123');
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
describe('fromAuthHeader', function() {
|
|
146
|
+
|
|
147
|
+
var extractor = extract_jwt.fromAuthHeaderAsBearerToken();
|
|
148
|
+
|
|
149
|
+
it('should return the value from the authorization header with default JWT auth scheme', function() {
|
|
150
|
+
var req = new Request()
|
|
151
|
+
req.headers['authorization'] = "bearer abcd123";
|
|
152
|
+
|
|
153
|
+
var token = extractor(req);
|
|
154
|
+
|
|
155
|
+
expect(token).to.equal('abcd123');
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
describe('fromExtractors', function() {
|
|
162
|
+
|
|
163
|
+
it('should raise a type error when the extractor is constructed with a non-array argument', function() {
|
|
164
|
+
this_should_throw = function() {
|
|
165
|
+
var extractor = extract_jwt.fromExtractors({})
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
expect(this_should_throw).to.throw(TypeError)
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
var extractor = extract_jwt.fromExtractors([extract_jwt.fromAuthHeaderAsBearerToken(), extract_jwt.fromHeader('authorization')]);
|
|
173
|
+
|
|
174
|
+
it('should return null when no extractor extracts token', function() {
|
|
175
|
+
var req = new Request();
|
|
176
|
+
|
|
177
|
+
var token = extractor(req);
|
|
178
|
+
|
|
179
|
+
expect(token).to.be.null;
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
it('should return token found by least extractor', function() {
|
|
184
|
+
var req = new Request()
|
|
185
|
+
req.headers['authorization'] = "abcd123";
|
|
186
|
+
|
|
187
|
+
var token = extractor(req);
|
|
188
|
+
|
|
189
|
+
expect(token).to.equal('abcd123');
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
it('should return token found by first extractor', function() {
|
|
194
|
+
var req = new Request()
|
|
195
|
+
req.headers['authorization'] = "bearer abcd123";
|
|
196
|
+
|
|
197
|
+
var token = extractor(req);
|
|
198
|
+
|
|
199
|
+
expect(token).to.equal('abcd123');
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
describe('versionOneCompatibility', function () {
|
|
206
|
+
|
|
207
|
+
describe('default behavior', function() {
|
|
208
|
+
|
|
209
|
+
var extractor = extract_jwt.versionOneCompatibility({});
|
|
210
|
+
|
|
211
|
+
it('should return the token in the default "JWT" auth header', function () {
|
|
212
|
+
var req = new Request();
|
|
213
|
+
req.headers['authorization'] = "JWT abcd123";
|
|
214
|
+
|
|
215
|
+
var token = extractor(req);
|
|
216
|
+
|
|
217
|
+
expect(token).to.equal('abcd123');
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
it('should return the token in the default "auth_token" body field', function () {
|
|
222
|
+
var req = new Request();
|
|
223
|
+
req.body = {};
|
|
224
|
+
req.body['auth_token'] = 'xyzabcd';
|
|
225
|
+
|
|
226
|
+
var token = extractor(req);
|
|
227
|
+
|
|
228
|
+
expect(token).to.equal('xyzabcd');
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
it('should return then token in the default "auth_token" query parameter', function () {
|
|
233
|
+
var req = new Request();
|
|
234
|
+
req.url += '?auth_token=abcd123';
|
|
235
|
+
|
|
236
|
+
var token = extractor(req);
|
|
237
|
+
|
|
238
|
+
expect(token).to.equal('abcd123');
|
|
239
|
+
});
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
describe('user supplied parameters', function() {
|
|
244
|
+
|
|
245
|
+
it('should return the token in an auth header with a user specified auth scheme', function() {
|
|
246
|
+
var opts = { authScheme: 'MY_CUSTOM_AUTH_SCHEME' };
|
|
247
|
+
var extractor = extract_jwt.versionOneCompatibility(opts);
|
|
248
|
+
var req = new Request();
|
|
249
|
+
req.headers['authorization'] = 'MY_CUSTOM_AUTH_SCHEME deadbeef';
|
|
250
|
+
|
|
251
|
+
var token = extractor(req);
|
|
252
|
+
|
|
253
|
+
expect(token).to.equal('deadbeef');
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
it('should return the token in a user supplied body field', function () {
|
|
258
|
+
var opts = { tokenBodyField: 'CUSTOM_BODY_FIELD' };
|
|
259
|
+
var extractor = extract_jwt.versionOneCompatibility(opts);
|
|
260
|
+
var req = new Request();
|
|
261
|
+
req.body = {};
|
|
262
|
+
req.body['CUSTOM_BODY_FIELD'] = 'badbeef';
|
|
263
|
+
|
|
264
|
+
var token = extractor(req);
|
|
265
|
+
|
|
266
|
+
expect(token).to.equal('badbeef');
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
it('should return the token in a user specified query parameter', function () {
|
|
271
|
+
var opts = { tokenQueryParameterName: 'CustomQueryParam' };
|
|
272
|
+
var extractor = extract_jwt.versionOneCompatibility(opts);
|
|
273
|
+
var req = new Request();
|
|
274
|
+
req.url += '?CustomQueryParam=deadbeef';
|
|
275
|
+
|
|
276
|
+
var token = extractor(req);
|
|
277
|
+
|
|
278
|
+
expect(token).to.equal('deadbeef');
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
});
|
|
287
|
+
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
var Strategy = require('../lib/strategy');
|
|
2
|
+
|
|
3
|
+
describe('Strategy', function() {
|
|
4
|
+
var strategy = new Strategy({jwtFromRequest: function(){}, secretOrKey: 'secret'}, function() {});
|
|
5
|
+
|
|
6
|
+
it('should be named jwt', function() {
|
|
7
|
+
expect(strategy.name).to.equal('jwt');
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
it('should throw if constructed without a verify callback', function() {
|
|
12
|
+
expect(function() {
|
|
13
|
+
var s = new Strategy({jwtFromRequest: function(r) {}, secretOrKey: 'secret'});
|
|
14
|
+
}).to.throw(TypeError, "JwtStrategy requires a verify callback");
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
it('should throw if constructed neither a secretOrKey or a secretOrKeyProvider arg', function() {
|
|
19
|
+
expect(function() {
|
|
20
|
+
var s = new Strategy({jwtFromRequest: function(r) {}, secretOrKey: null}, function() {});
|
|
21
|
+
}).to.throw(TypeError, 'JwtStrategy requires a secret or key');
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
it('should throw if constructed with both a secretOrKey and a secretOrKeyProvider', function () {
|
|
26
|
+
expect(function() {
|
|
27
|
+
var s = new Strategy({
|
|
28
|
+
secretOrKey: 'secret',
|
|
29
|
+
secretOrKeyProvider: function(req, token, done) {},
|
|
30
|
+
jwtFromRequest: function(r) {}
|
|
31
|
+
});
|
|
32
|
+
}).to.throw(TypeError);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
it('should throw if constructed without a jwtFromRequest arg', function() {
|
|
37
|
+
expect(function() {
|
|
38
|
+
var s = new Strategy({secretOrKey: 'secret'}, function() {});
|
|
39
|
+
}).to.throw(TypeError);
|
|
40
|
+
});
|
|
41
|
+
});
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
var Strategy = require('../lib/strategy')
|
|
2
|
+
, chai = require('chai')
|
|
3
|
+
, sinon = require('sinon')
|
|
4
|
+
, test_data= require('./testdata')
|
|
5
|
+
, url = require('url')
|
|
6
|
+
, extract_jwt = require('../lib/extract_jwt')
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
describe('Strategy', function() {
|
|
10
|
+
|
|
11
|
+
var mockVerifier = null;
|
|
12
|
+
|
|
13
|
+
before(function() {
|
|
14
|
+
// Replace the JWT Verfier with a stub to capture the value
|
|
15
|
+
// extracted from the request
|
|
16
|
+
mockVerifier = sinon.stub();
|
|
17
|
+
mockVerifier.callsArgWith(3, null, test_data.valid_jwt.payload);
|
|
18
|
+
Strategy.JwtVerifier = mockVerifier;
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
describe('handling request JWT present in request', function() {
|
|
24
|
+
var strategy;
|
|
25
|
+
|
|
26
|
+
before(function(done) {
|
|
27
|
+
strategy = new Strategy({
|
|
28
|
+
jwtFromRequest: function (r) { return test_data.valid_jwt.token; },
|
|
29
|
+
secretOrKey: 'secret'
|
|
30
|
+
},
|
|
31
|
+
function(jwt_payload, next) {
|
|
32
|
+
// Return values aren't important in this case
|
|
33
|
+
return next(null, {}, {});
|
|
34
|
+
}
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
mockVerifier.reset();
|
|
38
|
+
|
|
39
|
+
chai.passport.use(strategy)
|
|
40
|
+
.success(function(u, i) {
|
|
41
|
+
done();
|
|
42
|
+
})
|
|
43
|
+
.authenticate();
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
it("verifies the right jwt", function() {
|
|
48
|
+
sinon.assert.calledOnce(mockVerifier);
|
|
49
|
+
expect(mockVerifier.args[0][0]).to.equal(test_data.valid_jwt.token);
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
describe('handling request with NO JWT', function() {
|
|
56
|
+
|
|
57
|
+
var info;
|
|
58
|
+
|
|
59
|
+
before(function(done) {
|
|
60
|
+
strategy = new Strategy({jwtFromRequest: function(r) {}, secretOrKey: 'secret'}, function(jwt_payload, next) {
|
|
61
|
+
// Return values aren't important in this case
|
|
62
|
+
return next(null, {}, {});
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
mockVerifier.reset();
|
|
66
|
+
|
|
67
|
+
chai.passport.use(strategy)
|
|
68
|
+
.fail(function(i) {
|
|
69
|
+
info = i
|
|
70
|
+
done();
|
|
71
|
+
})
|
|
72
|
+
.req(function(req) {
|
|
73
|
+
req.body = {}
|
|
74
|
+
})
|
|
75
|
+
.authenticate();
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
it('should fail authentication', function() {
|
|
80
|
+
expect(info).to.be.an.object;
|
|
81
|
+
expect(info.message).to.equal("No auth token");
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
it('Should not try to verify anything', function() {
|
|
86
|
+
sinon.assert.notCalled(mockVerifier);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
describe('handling request url set to url.Url instead of string', function() {
|
|
92
|
+
|
|
93
|
+
var info;
|
|
94
|
+
|
|
95
|
+
before(function(done) {
|
|
96
|
+
strategy = new Strategy({jwtFromRequest: function(r) {}, secretOrKey: 'secret'}, function(jwt_payload, next) {
|
|
97
|
+
// Return values aren't important in this case
|
|
98
|
+
return next(null, {}, {});
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
mockVerifier.reset();
|
|
102
|
+
|
|
103
|
+
chai.passport.use(strategy)
|
|
104
|
+
.fail(function(i) {
|
|
105
|
+
info = i
|
|
106
|
+
done();
|
|
107
|
+
})
|
|
108
|
+
.req(function(req) {
|
|
109
|
+
req.body = {};
|
|
110
|
+
req.url = new url.Url('/');
|
|
111
|
+
})
|
|
112
|
+
.authenticate();
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
it('should fail authentication', function() {
|
|
117
|
+
expect(info).to.be.an.object;
|
|
118
|
+
expect(info.message).to.equal("No auth token");
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
});
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
var Strategy = require('../lib/strategy')
|
|
2
|
+
, chai = require('chai')
|
|
3
|
+
, test_data = require('./testdata')
|
|
4
|
+
, sinon = require('sinon')
|
|
5
|
+
, extract_jwt = require('../lib/extract_jwt');
|
|
6
|
+
|
|
7
|
+
describe('Strategy', function() {
|
|
8
|
+
|
|
9
|
+
describe('calling JWT validation function', function() {
|
|
10
|
+
var strategy;
|
|
11
|
+
|
|
12
|
+
before(function(done) {
|
|
13
|
+
verifyStub = sinon.stub();
|
|
14
|
+
verifyStub.callsArgWith(1, null, {}, {});
|
|
15
|
+
options = {};
|
|
16
|
+
options.issuer = "TestIssuer";
|
|
17
|
+
options.audience = "TestAudience";
|
|
18
|
+
options.secretOrKey = 'secret';
|
|
19
|
+
options.algorithms = ["HS256", "HS384"];
|
|
20
|
+
options.ignoreExpiration = false;
|
|
21
|
+
options.jsonWebTokenOptions = {
|
|
22
|
+
clockTolerance: 10,
|
|
23
|
+
maxAge: "1h",
|
|
24
|
+
};
|
|
25
|
+
options.jwtFromRequest = extract_jwt.fromAuthHeaderAsBearerToken();
|
|
26
|
+
strategy = new Strategy(options, verifyStub);
|
|
27
|
+
|
|
28
|
+
Strategy.JwtVerifier = sinon.stub();
|
|
29
|
+
Strategy.JwtVerifier.callsArgWith(3, null, test_data.valid_jwt.payload);
|
|
30
|
+
|
|
31
|
+
chai.passport.use(strategy)
|
|
32
|
+
.success(function(u, i) {
|
|
33
|
+
done();
|
|
34
|
+
})
|
|
35
|
+
.req(function(req) {
|
|
36
|
+
req.headers['authorization'] = "bearer " + test_data.valid_jwt.token;
|
|
37
|
+
})
|
|
38
|
+
.authenticate();
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
it('should call with the right secret as an argument', function() {
|
|
43
|
+
expect(Strategy.JwtVerifier.args[0][1]).to.equal('secret');
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
it('should call with the right issuer option', function() {
|
|
48
|
+
expect(Strategy.JwtVerifier.args[0][2]).to.be.an.object;
|
|
49
|
+
expect(Strategy.JwtVerifier.args[0][2].issuer).to.equal('TestIssuer');
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
it('should call with the right audience option', function() {
|
|
54
|
+
expect(Strategy.JwtVerifier.args[0][2]).to.be.an.object;
|
|
55
|
+
expect(Strategy.JwtVerifier.args[0][2].audience).to.equal('TestAudience');
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('should call with the right algorithms option', function() {
|
|
59
|
+
expect(Strategy.JwtVerifier.args[0][2]).to.be.an.object;
|
|
60
|
+
expect(Strategy.JwtVerifier.args[0][2].algorithms).to.eql(["HS256", "HS384"]);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('should call with the right ignoreExpiration option', function() {
|
|
64
|
+
expect(Strategy.JwtVerifier.args[0][2]).to.be.an.object;
|
|
65
|
+
expect(Strategy.JwtVerifier.args[0][2].ignoreExpiration).to.be.false;
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('should call with the right maxAge option', function() {
|
|
69
|
+
expect(Strategy.JwtVerifier.args[0][2]).to.be.an.object;
|
|
70
|
+
expect(Strategy.JwtVerifier.args[0][2].maxAge).to.equal('1h');
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('should call with the right clockTolerance option', function() {
|
|
74
|
+
expect(Strategy.JwtVerifier.args[0][2]).to.be.an.object;
|
|
75
|
+
expect(Strategy.JwtVerifier.args[0][2].clockTolerance).to.equal(10);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
describe('handling valid jwt', function() {
|
|
82
|
+
var strategy, payload;
|
|
83
|
+
|
|
84
|
+
before(function(done) {
|
|
85
|
+
strategy = new Strategy({jwtFromRequest: extract_jwt.fromAuthHeaderAsBearerToken(), secretOrKey: 'secret'}, function(jwt_payload, next) {
|
|
86
|
+
payload = jwt_payload;
|
|
87
|
+
next(null, {}, {});
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
// Mock successful verification
|
|
91
|
+
Strategy.JwtVerifier = sinon.stub();
|
|
92
|
+
Strategy.JwtVerifier.callsArgWith(3, null, test_data.valid_jwt.payload);
|
|
93
|
+
|
|
94
|
+
chai.passport.use(strategy)
|
|
95
|
+
.success(function(u, i) {
|
|
96
|
+
done();
|
|
97
|
+
})
|
|
98
|
+
.req(function(req) {
|
|
99
|
+
req.headers['authorization'] = "bearer " + test_data.valid_jwt.token;
|
|
100
|
+
})
|
|
101
|
+
.authenticate();
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
it('should call verify with the correct payload', function() {
|
|
106
|
+
expect(payload).to.deep.equal(test_data.valid_jwt.payload);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
describe('handling failing jwt', function() {
|
|
114
|
+
var strategy, info;
|
|
115
|
+
var verify_spy = sinon.spy();
|
|
116
|
+
|
|
117
|
+
before(function(done) {
|
|
118
|
+
|
|
119
|
+
strategy = new Strategy({jwtFromRequest: extract_jwt.fromAuthHeaderAsBearerToken(), secretOrKey: 'secret'}, verify_spy);
|
|
120
|
+
|
|
121
|
+
// Mock errored verification
|
|
122
|
+
Strategy.JwtVerifier = sinon.stub();
|
|
123
|
+
Strategy.JwtVerifier.callsArgWith(3, new Error("jwt expired"), false);
|
|
124
|
+
|
|
125
|
+
chai.passport.use(strategy)
|
|
126
|
+
.fail(function(i) {
|
|
127
|
+
info = i;
|
|
128
|
+
done();
|
|
129
|
+
})
|
|
130
|
+
.req(function(req) {
|
|
131
|
+
req.headers['authorization'] = "bearer " + test_data.valid_jwt.token;
|
|
132
|
+
})
|
|
133
|
+
.authenticate();
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
it('should not call verify', function() {
|
|
138
|
+
sinon.assert.notCalled(verify_spy);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
it('should fail with error message.', function() {
|
|
143
|
+
expect(info).to.be.an.object;
|
|
144
|
+
expect(info.message).to.equal('jwt expired');
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
describe('handling an invalid authentication header', function() {
|
|
151
|
+
var strategy, info;
|
|
152
|
+
var verify_spy = sinon.spy();
|
|
153
|
+
|
|
154
|
+
before(function(done) {
|
|
155
|
+
|
|
156
|
+
strategy = new Strategy({jwtFromRequest: extract_jwt.fromAuthHeaderAsBearerToken(), secretOrKey: 'secret'}, verify_spy);
|
|
157
|
+
|
|
158
|
+
chai.passport.use(strategy)
|
|
159
|
+
.fail(function(i) {
|
|
160
|
+
info = i;
|
|
161
|
+
done();
|
|
162
|
+
})
|
|
163
|
+
.req(function(req) {
|
|
164
|
+
req.headers['authorization'] = "malformed";
|
|
165
|
+
})
|
|
166
|
+
.authenticate();
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
it('should not call verify', function() {
|
|
171
|
+
sinon.assert.notCalled(verify_spy);
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
it('should fail with error message.', function() {
|
|
176
|
+
expect(info).to.be.an.object;
|
|
177
|
+
expect(info).to.be.an.instanceof(Error);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
});
|