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 Koa = require('koa');
|
9 | const koaJwt = require('koa-jwt');
|
10 |
|
11 | const jwksRsa = require('../src');
|
12 |
|
13 | describe('koaJwtSecret', () => {
|
14 | it('should throw error if options.jwksUri is null', () => {
|
15 | let err = null;
|
16 |
|
17 | try {
|
18 | new jwksRsa.koaJwtSecret();
|
19 | } catch (e) {
|
20 | err = e;
|
21 | }
|
22 |
|
23 | expect(err instanceof jwksRsa.ArgumentError).to.be.true;
|
24 | });
|
25 |
|
26 | it('should accept the secret function', () => {
|
27 | koaJwt({
|
28 | debug: true,
|
29 | secret: jwksRsa.koaJwtSecret({
|
30 | jwksUri: 'http://localhost/.well-known/jwks.json'
|
31 | })
|
32 | });
|
33 | });
|
34 |
|
35 | it('should not provide a key if token is invalid', done => {
|
36 |
|
37 | const app = new Koa();
|
38 | app.use(koaJwt({
|
39 | debug: true,
|
40 | secret: jwksRsa.koaJwtSecret({
|
41 | jwksUri: 'http://localhost/.well-known/jwks.json'
|
42 | })
|
43 | }));
|
44 |
|
45 | request(app.listen())
|
46 | .get('/')
|
47 | .set('Authorization', 'Bearer abc')
|
48 | .expect(401)
|
49 | .end((err, res) => {
|
50 | expect(res.text).to.equal('Invalid token');
|
51 | done();
|
52 | });
|
53 | });
|
54 |
|
55 | it('should not provide a key if token is HS256', (done) => {
|
56 | const app = new Koa();
|
57 | app.use(koaJwt({
|
58 | debug: true,
|
59 | secret: jwksRsa.koaJwtSecret({
|
60 | jwksUri: 'http://localhost/.well-known/jwks.json'
|
61 | })
|
62 | }));
|
63 |
|
64 | const token = createSymmetricToken('mykey', { sub: 'john' });
|
65 |
|
66 | request(app.listen())
|
67 | .get('/')
|
68 | .set('Authorization', `Bearer ${ token }`)
|
69 | .expect(401)
|
70 | .end((err, res) => {
|
71 | expect(res.text).to.equal('Missing / invalid token algorithm');
|
72 | done();
|
73 | });
|
74 | });
|
75 |
|
76 | it('should not provide a key if token is RS256 and no KID was provided', (done) => {
|
77 | const app = new Koa();
|
78 | app.use(koaJwt({
|
79 | debug: true,
|
80 | secret: jwksRsa.koaJwtSecret({
|
81 | jwksUri: 'http://localhost/.well-known/jwks.json'
|
82 | })
|
83 | }));
|
84 |
|
85 | const token = createToken(privateKey, null, { sub: 'john' });
|
86 | jwksEndpoint('http://localhost', [ { pub: publicKey, kid: '123' } ]);
|
87 |
|
88 | request(app.listen())
|
89 | .get('/')
|
90 | .set('Authorization', `Bearer ${ token }`)
|
91 | .expect(401)
|
92 | .end((err, res) => {
|
93 | expect(res.text).to.equal('Unable to find a signing key that matches \'null\'');
|
94 | done();
|
95 | });
|
96 | });
|
97 |
|
98 | it('should not provide a key if token is RS256 and invalid KID was provided', (done) => {
|
99 | const app = new Koa();
|
100 | app.use(koaJwt({
|
101 | debug: true,
|
102 | secret: jwksRsa.koaJwtSecret({
|
103 | jwksUri: 'http://localhost/.well-known/jwks.json'
|
104 | })
|
105 | }));
|
106 |
|
107 | const token = createToken(privateKey, '456', { sub: 'john' });
|
108 | jwksEndpoint('http://localhost', [ { pub: publicKey, kid: '123' } ]);
|
109 |
|
110 | request(app.listen())
|
111 | .get('/')
|
112 | .set('Authorization', `Bearer ${ token }`)
|
113 | .expect(401)
|
114 | .end((err, res) => {
|
115 | expect(res.text).to.equal('Unable to find a signing key that matches \'456\'');
|
116 | done();
|
117 | });
|
118 | });
|
119 |
|
120 | it('should not authenticate the user if KID matches but the keys don\'t', (done) => {
|
121 | const app = new Koa();
|
122 | app.use(koaJwt({
|
123 | debug: true,
|
124 | secret: jwksRsa.koaJwtSecret({
|
125 | jwksUri: 'http://localhost/.well-known/jwks.json'
|
126 | })
|
127 | }));
|
128 |
|
129 | const token = createToken(privateKey, '123', { sub: 'john' });
|
130 | jwksEndpoint('http://localhost', [ { pub: randomPublicKey1, kid: '123' } ]);
|
131 |
|
132 | request(app.listen())
|
133 | .get('/')
|
134 | .set('Authorization', `Bearer ${ token }`)
|
135 | .expect(401)
|
136 | .end((err, res) => {
|
137 | expect(res.text).to.equal('invalid signature');
|
138 | done();
|
139 | });
|
140 | });
|
141 |
|
142 | it('should allow returning an error if key not found', (done) => {
|
143 |
|
144 | const app = new Koa();
|
145 | app.use(koaJwt({
|
146 | debug: true,
|
147 | secret: jwksRsa.koaJwtSecret({
|
148 | jwksUri: 'http://localhost/.well-known/jwks.json',
|
149 | handleSigningKeyError: (err) => {
|
150 | if (err instanceof jwksRsa.SigningKeyNotFoundError) {
|
151 | return Promise.resolve(
|
152 | new Error('this is bad')
|
153 | );
|
154 | }
|
155 | }
|
156 | })
|
157 | }));
|
158 |
|
159 | const token = createToken(privateKey, '456', { sub: 'john' });
|
160 | jwksEndpoint('http://localhost', [ { pub: randomPublicKey1, kid: '123' } ]);
|
161 |
|
162 | request(app.listen())
|
163 | .get('/')
|
164 | .set('Authorization', `Bearer ${ token }`)
|
165 | .expect(401)
|
166 | .end((err, res) => {
|
167 | expect(res.text).to.equal('this is bad');
|
168 | done();
|
169 | });
|
170 | });
|
171 |
|
172 | it('should work if the token matches a signing key', (done) => {
|
173 | const app = new Koa();
|
174 | app.use(koaJwt({
|
175 | debug: true,
|
176 | secret: jwksRsa.koaJwtSecret({
|
177 | jwksUri: 'http://localhost/.well-known/jwks.json'
|
178 | }),
|
179 | algorithms: [ 'RS256' ]
|
180 | }));
|
181 | app.use((ctx) => {
|
182 | ctx.body = ctx.state.user;
|
183 | ctx.status = 200;
|
184 | });
|
185 |
|
186 | const token = createToken(privateKey, '123', { sub: 'john' });
|
187 | jwksEndpoint('http://localhost', [ { pub: publicKey, kid: '123' } ]);
|
188 |
|
189 | request(app.listen())
|
190 | .get('/')
|
191 | .set('Authorization', `Bearer ${ token }`)
|
192 | .expect(200)
|
193 | .end((err, res) => {
|
194 | expect(res.body.sub).to.equal('john');
|
195 | done();
|
196 | });
|
197 | });
|
198 |
|
199 | });
|