1 | import request from 'supertest';
|
2 | import { expect } from 'chai';
|
3 |
|
4 | import { jwksEndpoint } from './mocks/jwks';
|
5 | import { publicKey, privateKey, randomPublicKey1 } from './mocks/keys';
|
6 | import { createToken, createSymmetricToken } from './mocks/tokens';
|
7 |
|
8 | const Express = require('express');
|
9 | const passport = require('passport');
|
10 | const JwtStrategy = require('passport-jwt').Strategy;
|
11 | const ExtractJwt = require('passport-jwt').ExtractJwt;
|
12 |
|
13 | const jwksRsa = require('../src');
|
14 |
|
15 | describe('passportJwtSecret', () => {
|
16 | it('should throw error if options.jwksUri is null', () => {
|
17 | let err = null;
|
18 |
|
19 | try {
|
20 | new jwksRsa.passportJwtSecret();
|
21 | } catch (e) {
|
22 | err = e;
|
23 | }
|
24 |
|
25 | expect(err instanceof jwksRsa.ArgumentError).to.be.true;
|
26 | });
|
27 |
|
28 | it('should accept the secret function', () => {
|
29 | new JwtStrategy(
|
30 | {
|
31 | secretOrKeyProvider: jwksRsa.passportJwtSecret({
|
32 | jwksUri: 'http://localhost/.well-known/jwks.json'
|
33 | }),
|
34 | jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken()
|
35 | },
|
36 | (jwt_payload, done) => done(null, jwt_payload)
|
37 | );
|
38 | });
|
39 |
|
40 | it('should not provide a key if token is invalid', done => {
|
41 | const app = new Express();
|
42 | passport.use(
|
43 | new JwtStrategy(
|
44 | {
|
45 | secretOrKeyProvider: jwksRsa.passportJwtSecret({
|
46 | jwksUri: 'http://localhost/.well-known/jwks.json'
|
47 | }),
|
48 | jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken()
|
49 | },
|
50 | (jwt_payload, done) => done(null, jwt_payload)
|
51 | )
|
52 | );
|
53 |
|
54 | app.get(
|
55 | '/',
|
56 | (req, res, next) => {
|
57 | req.flash = (type, msg) => {
|
58 | res.send(msg);
|
59 | };
|
60 | next();
|
61 | },
|
62 | passport.authenticate('jwt', { session: false, failureFlash: true }),
|
63 | (req, res) => {
|
64 | res.send('OK');
|
65 | }
|
66 | );
|
67 |
|
68 | request(app.listen())
|
69 | .get('/')
|
70 | .set('Authorization', 'Bearer abc')
|
71 | .expect(401)
|
72 | .end((err, res) => {
|
73 | expect(res.text).to.equal('jwt malformed');
|
74 | done();
|
75 | });
|
76 | });
|
77 |
|
78 | it('should not provide a key if token is HS256', done => {
|
79 | const app = new Express();
|
80 | passport.use(
|
81 | new JwtStrategy(
|
82 | {
|
83 | secretOrKeyProvider: jwksRsa.passportJwtSecret({
|
84 | jwksUri: 'http://localhost/.well-known/jwks.json'
|
85 | }),
|
86 | jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken()
|
87 | },
|
88 | (jwt_payload, done) => done(null, jwt_payload)
|
89 | )
|
90 | );
|
91 |
|
92 | app.get(
|
93 | '/',
|
94 | (req, res, next) => {
|
95 | req.flash = (type, msg) => {
|
96 | res.send(msg);
|
97 | };
|
98 | next();
|
99 | },
|
100 | passport.authenticate('jwt', { session: false, failureFlash: true }),
|
101 | (req, res) => {
|
102 | res.send('OK');
|
103 | }
|
104 | );
|
105 |
|
106 | const token = createSymmetricToken('mykey', { sub: 'john' });
|
107 |
|
108 | request(app.listen())
|
109 | .get('/')
|
110 | .set('Authorization', `Bearer ${token}`)
|
111 | .expect(401)
|
112 | .end((err, res) => {
|
113 | expect(res.text).to.equal('secret or public key must be provided');
|
114 | done();
|
115 | });
|
116 | });
|
117 |
|
118 | it('should not provide a key if token is RS256 and no KID was provided', done => {
|
119 | const app = new Express();
|
120 | passport.use(
|
121 | new JwtStrategy(
|
122 | {
|
123 | secretOrKeyProvider: jwksRsa.passportJwtSecret({
|
124 | jwksUri: 'http://localhost/.well-known/jwks.json'
|
125 | }),
|
126 | jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken()
|
127 | },
|
128 | (jwt_payload, done) => done(null, jwt_payload)
|
129 | )
|
130 | );
|
131 |
|
132 | app.get(
|
133 | '/',
|
134 | (req, res, next) => {
|
135 | req.flash = (type, msg) => {
|
136 | res.send(msg);
|
137 | };
|
138 | next();
|
139 | },
|
140 | passport.authenticate('jwt', { session: false, failureFlash: true }),
|
141 | (req, res) => {
|
142 | res.send('OK');
|
143 | }
|
144 | );
|
145 |
|
146 | const token = createToken(privateKey, null, { sub: 'john' });
|
147 | jwksEndpoint('http://localhost', [ { pub: publicKey, kid: '123' } ]);
|
148 |
|
149 | request(app.listen())
|
150 | .get('/')
|
151 | .set('Authorization', `Bearer ${token}`)
|
152 | .expect(401)
|
153 | .end((err, res) => {
|
154 | expect(res.text).to.equal('secret or public key must be provided');
|
155 | done();
|
156 | });
|
157 | });
|
158 |
|
159 | it('should not provide a key if token is RS256 and invalid KID was provided', done => {
|
160 | const app = new Express();
|
161 | passport.use(
|
162 | new JwtStrategy(
|
163 | {
|
164 | secretOrKeyProvider: jwksRsa.passportJwtSecret({
|
165 | jwksUri: 'http://localhost/.well-known/jwks.json'
|
166 | }),
|
167 | jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken()
|
168 | },
|
169 | (jwt_payload, done) => {
|
170 | done(null, jwt_payload);
|
171 | }
|
172 | )
|
173 | );
|
174 |
|
175 | app.get(
|
176 | '/',
|
177 | (req, res, next) => {
|
178 | req.flash = (type, msg) => {
|
179 | res.send(msg);
|
180 | };
|
181 | next();
|
182 | },
|
183 | passport.authenticate('jwt', { session: false, failureFlash: true }),
|
184 | (req, res) => {
|
185 | res.send('OK');
|
186 | }
|
187 | );
|
188 |
|
189 | const token = createToken(privateKey, '456', { sub: 'john' });
|
190 | jwksEndpoint('http://localhost', [ { pub: publicKey, kid: '123' } ]);
|
191 |
|
192 | request(app.listen())
|
193 | .get('/')
|
194 | .set('Authorization', `Bearer ${token}`)
|
195 | .expect(401)
|
196 | .end((err, res) => {
|
197 | expect(res.text).to.equal('secret or public key must be provided');
|
198 | done();
|
199 | });
|
200 | });
|
201 |
|
202 | it('should not authenticate the user if KID matches but the keys don\'t', done => {
|
203 | const app = new Express();
|
204 | passport.use(
|
205 | new JwtStrategy(
|
206 | {
|
207 | secretOrKeyProvider: jwksRsa.passportJwtSecret({
|
208 | jwksUri: 'http://localhost/.well-known/jwks.json'
|
209 | }),
|
210 | jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken()
|
211 | },
|
212 | (jwt_payload, done) => {
|
213 | done(null, jwt_payload);
|
214 | }
|
215 | )
|
216 | );
|
217 |
|
218 | app.get(
|
219 | '/',
|
220 | (req, res, next) => {
|
221 | req.flash = (type, msg) => {
|
222 | res.send(msg);
|
223 | };
|
224 | next();
|
225 | },
|
226 | passport.authenticate('jwt', { session: false, failureFlash: true }),
|
227 | (req, res) => {
|
228 | res.send('OK');
|
229 | }
|
230 | );
|
231 |
|
232 | const token = createToken(privateKey, '123', { sub: 'john' });
|
233 | jwksEndpoint('http://localhost', [ { pub: randomPublicKey1, kid: '123' } ]);
|
234 |
|
235 | request(app.listen())
|
236 | .get('/')
|
237 | .set('Authorization', `Bearer ${token}`)
|
238 | .expect(401)
|
239 | .end((err, res) => {
|
240 | expect(res.text).to.equal('invalid signature');
|
241 | done();
|
242 | });
|
243 | });
|
244 |
|
245 | it('should allow returning an error if key not found', done => {
|
246 | const app = new Express();
|
247 | passport.use(
|
248 | new JwtStrategy(
|
249 | {
|
250 | secretOrKeyProvider: jwksRsa.passportJwtSecret({
|
251 | jwksUri: 'http://localhost/.well-known/jwks.json',
|
252 | handleSigningKeyError: (err, cb) => {
|
253 | if (err instanceof jwksRsa.SigningKeyNotFoundError) {
|
254 | return cb(new Error('this is bad'));
|
255 | }
|
256 | }
|
257 | }),
|
258 | jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken()
|
259 | },
|
260 | (jwt_payload, done) => done(null, jwt_payload)
|
261 | )
|
262 | );
|
263 |
|
264 | app.get(
|
265 | '/',
|
266 | (req, res, next) => {
|
267 | req.flash = (type, msg) => {
|
268 | res.send(msg);
|
269 | };
|
270 | next();
|
271 | },
|
272 | passport.authenticate('jwt', { session: false, failureFlash: true }),
|
273 | (req, res) => {
|
274 | res.send('OK');
|
275 | }
|
276 | );
|
277 |
|
278 | const token = createToken(privateKey, '456', { sub: 'john' });
|
279 | jwksEndpoint('http://localhost', [ { pub: randomPublicKey1, kid: '123' } ]);
|
280 |
|
281 | request(app.listen())
|
282 | .get('/')
|
283 | .set('Authorization', `Bearer ${token}`)
|
284 | .expect(401)
|
285 | .end((err, res) => {
|
286 | expect(res.text).to.equal('this is bad');
|
287 | done();
|
288 | });
|
289 | });
|
290 |
|
291 | it('should work if the token matches a signing key', done => {
|
292 | const app = new Express();
|
293 | passport.use(
|
294 | new JwtStrategy(
|
295 | {
|
296 | secretOrKeyProvider: jwksRsa.passportJwtSecret({
|
297 | jwksUri: 'http://localhost/.well-known/jwks.json'
|
298 | }),
|
299 | jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
|
300 | algorithms: [ 'RS256' ]
|
301 | },
|
302 | (jwt_payload, done) => done(null, jwt_payload)
|
303 | )
|
304 | );
|
305 |
|
306 | app.get(
|
307 | '/',
|
308 | passport.authenticate('jwt', { session: false }),
|
309 | (req, res) => {
|
310 | res.json(req.user);
|
311 | }
|
312 | );
|
313 |
|
314 | const token = createToken(privateKey, '123', { sub: 'john' });
|
315 | jwksEndpoint('http://localhost', [ { pub: publicKey, kid: '123' } ]);
|
316 |
|
317 | request(app.listen())
|
318 | .get('/')
|
319 | .set('Authorization', `Bearer ${token}`)
|
320 | .expect(200)
|
321 | .end((err, res) => {
|
322 | expect(res.body.sub).to.equal('john');
|
323 | done();
|
324 | });
|
325 | });
|
326 | });
|