1 | import nock from 'nock';
|
2 | import { expect } from 'chai';
|
3 |
|
4 | import { x5cMultiple } from './keys';
|
5 | import { JwksClient } from '../src/JwksClient';
|
6 |
|
7 | describe('JwksClient', () => {
|
8 | const jwksHost = 'http://my-authz-server';
|
9 | const proxy = 'my-proxy-server:2815';
|
10 |
|
11 | beforeEach(() => {
|
12 | nock.cleanAll();
|
13 | });
|
14 |
|
15 | describe('#getKeys', () => {
|
16 | it('should handle errors', done => {
|
17 | nock(jwksHost)
|
18 | .get('/.well-known/jwks.json')
|
19 | .reply(500, 'Unknown Server Error');
|
20 |
|
21 | const client = new JwksClient({
|
22 | jwksUri: `${jwksHost}/.well-known/jwks.json`
|
23 | });
|
24 |
|
25 | client.getKeys(err => {
|
26 | expect(err).not.to.be.null;
|
27 | expect(err.message).to.equal('Unknown Server Error');
|
28 | done();
|
29 | });
|
30 | });
|
31 |
|
32 | it('should return keys', done => {
|
33 | nock(jwksHost)
|
34 | .get('/.well-known/jwks.json')
|
35 | .reply(200, {
|
36 | keys: [
|
37 | {
|
38 | alg: 'RS256',
|
39 | kty: 'RSA',
|
40 | use: 'sig',
|
41 | x5c: [ 'pk1' ],
|
42 | kid: 'ABC'
|
43 | },
|
44 | {
|
45 | alg: 'RS256',
|
46 | kty: 'RSA',
|
47 | use: 'sig',
|
48 | x5c: [],
|
49 | kid: '123'
|
50 | }
|
51 | ]
|
52 | });
|
53 |
|
54 | const client = new JwksClient({
|
55 | jwksUri: `${jwksHost}/.well-known/jwks.json`
|
56 | });
|
57 |
|
58 | client.getKeys((err, keys) => {
|
59 | expect(err).to.be.null;
|
60 | expect(keys).not.to.be.null;
|
61 | expect(keys.length).to.equal(2);
|
62 | expect(keys[1].kid).to.equal('123');
|
63 | done();
|
64 | });
|
65 | });
|
66 |
|
67 | it('should set request agentOptions when provided', done => {
|
68 | nock(jwksHost)
|
69 | .get('./well-known/jwks.json')
|
70 | .reply(function() {
|
71 | expect(this.req.agentOptions).not.to.be.null;
|
72 | expect(this.req.agentOptions['ca']).to.be.equal('loadCA()');
|
73 | return 200;
|
74 | });
|
75 |
|
76 | const client = new JwksClient({
|
77 | jwksUri: `${jwksHost}/.well-known/jwks.json`,
|
78 | requestAgentOptions: {
|
79 | ca: 'loadCA()'
|
80 | }
|
81 | });
|
82 |
|
83 | client.getKeys(() => {
|
84 | done();
|
85 | });
|
86 | });
|
87 |
|
88 | it('should not set request agentOptions by default', done => {
|
89 | nock(jwksHost)
|
90 | .get('/.well-known/jwks.json')
|
91 | .reply(function() {
|
92 | expect(this.req).to.not.have.property('agentOptions');
|
93 | return 200;
|
94 | });
|
95 |
|
96 | const client = new JwksClient({
|
97 | jwksUri: `${jwksHost}/.well-known/jwks.json`
|
98 | });
|
99 |
|
100 | client.getKeys(() => {
|
101 | done();
|
102 | });
|
103 | });
|
104 |
|
105 | it('should send extra header', done => {
|
106 | nock(jwksHost)
|
107 | .get('/.well-known/jwks.json')
|
108 | .reply(function() {
|
109 | expect(this.req.headers).not.to.be.null;
|
110 | expect(this.req.headers['user-agent']).to.be.equal('My-bot');
|
111 | expect(Object.keys(this.req.headers).length).to.be.equal(3);
|
112 | return (
|
113 | 200,
|
114 | {
|
115 | keys: [
|
116 | {
|
117 | alg: 'RS256',
|
118 | kty: 'RSA',
|
119 | use: 'sig',
|
120 | x5c: [ 'pk1' ],
|
121 | kid: 'ABC'
|
122 | },
|
123 | {
|
124 | alg: 'RS256',
|
125 | kty: 'RSA',
|
126 | use: 'sig',
|
127 | x5c: [],
|
128 | kid: '123'
|
129 | }
|
130 | ]
|
131 | }
|
132 | );
|
133 | });
|
134 |
|
135 | const client = new JwksClient({
|
136 | jwksUri: `${jwksHost}/.well-known/jwks.json`,
|
137 | requestHeaders: {
|
138 | 'User-Agent': 'My-bot'
|
139 | }
|
140 | });
|
141 |
|
142 | client.getKeys(() => {
|
143 | done();
|
144 | });
|
145 | });
|
146 |
|
147 | it('should not send the extra headers when not provided', done => {
|
148 | nock(jwksHost)
|
149 | .get('/.well-known/jwks.json')
|
150 | .reply(function() {
|
151 | expect(this.req.headers).not.to.be.null;
|
152 | expect(this.req.headers['accept']).not.to.be.undefined;
|
153 | expect(this.req.headers['host']).not.to.be.undefined;
|
154 | expect(Object.keys(this.req.headers).length).to.be.equal(2);
|
155 | return (
|
156 | 200,
|
157 | {
|
158 | keys: [
|
159 | {
|
160 | alg: 'RS256',
|
161 | kty: 'RSA',
|
162 | use: 'sig',
|
163 | x5c: [ 'pk1' ],
|
164 | kid: 'ABC'
|
165 | },
|
166 | {
|
167 | alg: 'RS256',
|
168 | kty: 'RSA',
|
169 | use: 'sig',
|
170 | x5c: [],
|
171 | kid: '123'
|
172 | }
|
173 | ]
|
174 | }
|
175 | );
|
176 | });
|
177 |
|
178 | const client = new JwksClient({
|
179 | jwksUri: `${jwksHost}/.well-known/jwks.json`
|
180 | });
|
181 |
|
182 | client.getKeys(() => {
|
183 | done();
|
184 | });
|
185 | });
|
186 |
|
187 | it('should use a proxy if specified', done => {
|
188 | const expectedError = { message: 'expectedError' };
|
189 | nock(`http://${proxy}`)
|
190 | .get(() => true)
|
191 | .replyWithError(expectedError);
|
192 |
|
193 | const client = new JwksClient({
|
194 | jwksUri: `${jwksHost}/.well-known/jwks.json`,
|
195 | requestHeaders: {
|
196 | 'User-Agent': 'My-bot'
|
197 | },
|
198 | proxy: `http://username:password@${proxy}`
|
199 | });
|
200 |
|
201 | client.getKeys((err) => {
|
202 | expect(err).to.equal(expectedError);
|
203 | done();
|
204 | });
|
205 | });
|
206 | });
|
207 |
|
208 | describe('#getSigningKeys', () => {
|
209 | it('should handle errors', done => {
|
210 | nock(jwksHost)
|
211 | .get('/.well-known/jwks.json')
|
212 | .reply(500, 'Unknown Server Error');
|
213 |
|
214 | const client = new JwksClient({
|
215 | jwksUri: `${jwksHost}/.well-known/jwks.json`
|
216 | });
|
217 |
|
218 | client.getSigningKeys(err => {
|
219 | expect(err).not.to.be.null;
|
220 | expect(err.message).to.equal('Unknown Server Error');
|
221 | done();
|
222 | });
|
223 | });
|
224 |
|
225 | it('should return signing keys (with x5c and mod/exp)', done => {
|
226 | nock(jwksHost)
|
227 | .get('/.well-known/jwks.json')
|
228 | .reply(200, {
|
229 | keys: [
|
230 | {
|
231 | alg: 'RS256',
|
232 | kty: 'RSA',
|
233 | use: 'sig',
|
234 | x5c: [
|
235 | 'MIIDDTCCAfWgAwIBAgIJAJVkuSv2H8mDMA0GCSqGSIb3DQEBBQUAMB0xGzAZBgNVBAMMEnNhbmRyaW5vLmF1dGgwLmNvbTAeFw0xNDA1MTQyMTIyMjZaFw0yODAxMjEyMTIyMjZaMB0xGzAZBgNVBAMMEnNhbmRyaW5vLmF1dGgwLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL6jWASkHhXz5Ug6t5BsYBrXDIgrWu05f3oq2fE+5J5REKJiY0Ddc+Kda34ZwOptnUoef3JwKPDAckTJQDugweNNZPwOmFMRKj4xqEpxEkIX8C+zHs41Q6x54ZZy0xU+WvTGcdjzyZTZ/h0iOYisswFQT/s6750tZG0BOBtZ5qS/80tmWH7xFitgewdWteJaASE/eO1qMtdNsp9fxOtN5U/pZDUyFm3YRfOcODzVqp3wOz+dcKb7cdZN11EYGZOkjEekpcedzHCo9H4aOmdKCpytqL/9FXoihcBMg39s1OW3cfwfgf5/kvOJdcqR4PoATQTfsDVoeMWVB4XLGR6SC5kCAwEAAaNQME4wHQYDVR0OBBYEFHDYn9BQdup1CoeoFi0Rmf5xn/W9MB8GA1UdIwQYMBaAFHDYn9BQdup1CoeoFi0Rmf5xn/W9MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAGLpQZdd2ICVnGjc6CYfT3VNoujKYWk7E0shGaCXFXptrZ8yaryfo6WAizTfgOpQNJH+Jz+QsCjvkRt6PBSYX/hb5OUDU2zNJN48/VOw57nzWdjI70H2Ar4oJLck36xkIRs/+QX+mSNCjZboRwh0LxanXeALHSbCgJkbzWbjVnfJEQUP9P/7NGf0MkO5I95C/Pz9g91y8gU+R3imGppLy9Zx+OwADFwKAEJak4JrNgcjHBQenakAXnXP6HG4hHH4MzO8LnLiKv8ZkKVL67da/80PcpO0miMNPaqBBMd2Cy6GzQYE0ag6k0nk+DMIFn7K+o21gjUuOEJqIbAvhbf2KcM='
|
236 | ],
|
237 | n:
|
238 | 'vqNYBKQeFfPlSDq3kGxgGtcMiCta7Tl_eirZ8T7knlEQomJjQN1z4p1rfhnA6m2dSh5_cnAo8MByRMlAO6DB401k_A6YUxEqPjGoSnESQhfwL7MezjVDrHnhlnLTFT5a9MZx2PPJlNn-HSI5iKyzAVBP-zrvnS1kbQE4G1nmpL_zS2ZYfvEWK2B7B1a14loBIT947Woy102yn1_E603lT-lkNTIWbdhF85w4PNWqnfA7P51wpvtx1k3XURgZk6SMR6Slx53McKj0fho6Z0oKnK2ov_0VeiKFwEyDf2zU5bdx_B-B_n-S84l1ypHg-gBNBN-wNWh4xZUHhcsZHpILmQ',
|
239 | e: 'AQAB',
|
240 | kid: 'RkI5MjI5OUY5ODc1N0Q4QzM0OUYzNkVGMTJDOUEzQkFCOTU3NjE2Rg',
|
241 | x5t: 'RkI5MjI5OUY5ODc1N0Q4QzM0OUYzNkVGMTJDOUEzQkFCOTU3NjE2Rg'
|
242 | },
|
243 | {
|
244 | kid: 'IdTokenSigningKeyContainer',
|
245 | use: 'sig',
|
246 | kty: 'RSA',
|
247 | e: 'AQAB',
|
248 | n:
|
249 | 'tLDZVZ2Eq_DFwNp24yeSq_Ha0MYbYOJs_WXIgVxQGabu5cZ9561OUtYWdB6xXXZLaZxFG02P5U2rC_CT1r0lPfC_KHYrviJ5Y_Ekif7iFV_1omLAiRksQziwA1i-hND32N5kxwEGNmZViVjWMBZ43wbIdWss4IMhrJy1WNQ07Fqp1Ee6o7QM1hTBve7bbkJkUAfjtC7mwIWqZdWoYIWBTZRXvhMgs_Aeb_pnDekosqDoWQ5aMklk3NvaaBBESqlRAJZUUf5WDFoJh7yRELOFF4lWJxtArTEiQPWVTX6PCs0klVPU6SRQqrtc4kKLCp1AC5EJqPYRGiEJpSz2nUhmAQ'
|
250 | }
|
251 | ]
|
252 | });
|
253 |
|
254 | const client = new JwksClient({
|
255 | jwksUri: `${jwksHost}/.well-known/jwks.json`
|
256 | });
|
257 |
|
258 | client.getSigningKeys((err, keys) => {
|
259 | expect(err).to.be.null;
|
260 | expect(keys).not.to.be.null;
|
261 | expect(keys.length).to.equal(2);
|
262 | const pubkey0 = keys[0].publicKey || keys[0].rsaPublicKey;
|
263 | expect(pubkey0).not.to.be.null;
|
264 | expect(keys[0].getPublicKey()).to.equal(keys[0].publicKey);
|
265 | expect(keys[1].kid).to.equal('IdTokenSigningKeyContainer');
|
266 | expect(keys[0].kid).to.equal('RkI5MjI5OUY5ODc1N0Q4QzM0OUYzNkVGMTJDOUEzQkFCOTU3NjE2Rg');
|
267 | const pubkey1 = keys[1].publicKey || keys[1].rsaPublicKey;
|
268 | expect(pubkey1).not.to.be.null;
|
269 | expect(keys[1].getPublicKey()).to.equal(keys[1].rsaPublicKey);
|
270 | done();
|
271 | });
|
272 | });
|
273 |
|
274 | it('should return signing keys (with x5c)', done => {
|
275 | nock(jwksHost)
|
276 | .get('/.well-known/jwks.json')
|
277 | .reply(200, {
|
278 | keys: [
|
279 | {
|
280 | alg: 'RS256',
|
281 | kty: 'RSA',
|
282 | use: 'sig',
|
283 | x5c: [
|
284 | 'MIIDDTCCAfWgAwIBAgIJAJVkuSv2H8mDMA0GCSqGSIb3DQEBBQUAMB0xGzAZBgNVBAMMEnNhbmRyaW5vLmF1dGgwLmNvbTAeFw0xNDA1MTQyMTIyMjZaFw0yODAxMjEyMTIyMjZaMB0xGzAZBgNVBAMMEnNhbmRyaW5vLmF1dGgwLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL6jWASkHhXz5Ug6t5BsYBrXDIgrWu05f3oq2fE+5J5REKJiY0Ddc+Kda34ZwOptnUoef3JwKPDAckTJQDugweNNZPwOmFMRKj4xqEpxEkIX8C+zHs41Q6x54ZZy0xU+WvTGcdjzyZTZ/h0iOYisswFQT/s6750tZG0BOBtZ5qS/80tmWH7xFitgewdWteJaASE/eO1qMtdNsp9fxOtN5U/pZDUyFm3YRfOcODzVqp3wOz+dcKb7cdZN11EYGZOkjEekpcedzHCo9H4aOmdKCpytqL/9FXoihcBMg39s1OW3cfwfgf5/kvOJdcqR4PoATQTfsDVoeMWVB4XLGR6SC5kCAwEAAaNQME4wHQYDVR0OBBYEFHDYn9BQdup1CoeoFi0Rmf5xn/W9MB8GA1UdIwQYMBaAFHDYn9BQdup1CoeoFi0Rmf5xn/W9MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAGLpQZdd2ICVnGjc6CYfT3VNoujKYWk7E0shGaCXFXptrZ8yaryfo6WAizTfgOpQNJH+Jz+QsCjvkRt6PBSYX/hb5OUDU2zNJN48/VOw57nzWdjI70H2Ar4oJLck36xkIRs/+QX+mSNCjZboRwh0LxanXeALHSbCgJkbzWbjVnfJEQUP9P/7NGf0MkO5I95C/Pz9g91y8gU+R3imGppLy9Zx+OwADFwKAEJak4JrNgcjHBQenakAXnXP6HG4hHH4MzO8LnLiKv8ZkKVL67da/80PcpO0miMNPaqBBMd2Cy6GzQYE0ag6k0nk+DMIFn7K+o21gjUuOEJqIbAvhbf2KcM='
|
285 | ],
|
286 | n:
|
287 | 'vqNYBKQeFfPlSDq3kGxgGtcMiCta7Tl_eirZ8T7knlEQomJjQN1z4p1rfhnA6m2dSh5_cnAo8MByRMlAO6DB401k_A6YUxEqPjGoSnESQhfwL7MezjVDrHnhlnLTFT5a9MZx2PPJlNn-HSI5iKyzAVBP-zrvnS1kbQE4G1nmpL_zS2ZYfvEWK2B7B1a14loBIT947Woy102yn1_E603lT-lkNTIWbdhF85w4PNWqnfA7P51wpvtx1k3XURgZk6SMR6Slx53McKj0fho6Z0oKnK2ov_0VeiKFwEyDf2zU5bdx_B-B_n-S84l1ypHg-gBNBN-wNWh4xZUHhcsZHpILmQ',
|
288 | e: 'AQAB',
|
289 | kid: 'RkI5MjI5OUY5ODc1N0Q4QzM0OUYzNkVGMTJDOUEzQkFCOTU3NjE2Rg',
|
290 | x5t: 'RkI5MjI5OUY5ODc1N0Q4QzM0OUYzNkVGMTJDOUEzQkFCOTU3NjE2Rg'
|
291 | },
|
292 | {
|
293 | alg: 'RS256',
|
294 | kty: 'RSA',
|
295 | use: 'sig',
|
296 | nbf: 123,
|
297 | x5c: [
|
298 | 'MIIDGzCCAgOgAwIBAgIJAPQM5+PwmOcPMA0GCSqGSIb3DQEBCwUAMCQxIjAgBgNVBAMMGXNhbmRyaW5vLWRldi5ldS5hdXRoMC5jb20wHhcNMTUwMzMxMDkwNTQ3WhcNMjgxMjA3MDkwNTQ3WjAkMSIwIAYDVQQDDBlzYW5kcmluby1kZXYuZXUuYXV0aDAuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv/SECtT7H4rxKtX2HpGhSyeYTe3Vet8YQpjBAr+1TnQ1fcYfvfmnVRHvhmTwABktD1erF1lxFsrRw92yBDOHlL7lj1n2fcfLftSoStgvRHVg52kR+CkBVQ6/mF1lYkefIjik6YRMf55Eu4FqDyVG2dgd5EA8kNO4J8OPc7vAtZyXrRYOZjVXbEgyjje/V+OpMQxAHP2Er11TLuzJjioP0ICVqhAZdq2sLk7agoxn64md6fqOk4N+7lJkU4+412VD0qYwKxD7nGsEclYawKoZD9/xhCk2qfQ/HptIumrdQ5ox3Sq5t2a7VKa41dBUQ1MQtXG2iY7S9RlfcMIyQwGhOQIDAQABo1AwTjAdBgNVHQ4EFgQUHpS1fvO/54G2c1VpEDNUZRSl44gwHwYDVR0jBBgwFoAUHpS1fvO/54G2c1VpEDNUZRSl44gwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAtm9I0nr6eXF5aq4yllfiqZcQ6mKrJLH9Rm4Jv+olniNynTcnpwprRVLToIawc8MmzIGZTtCn7u+dSxWf1UNE+SH7XgEnGtO74239vleEx1+Tf5viIdsnCxgvFiPdOqRlc9KcFSWd6a7RzcglnyU7GEx0K5GLv1wPA6qEM+3uwNwjAyVSu5dFw8kCfaSvlk5rXKRUzSoW9NVomw6+tADR8vMZS+4KThZ+4GH0rMN4KjIaRFxW8OMVYOn12uq33fLCd6MuPHW/rklxLbQBoHIU/ClNhbD0t6f00w9lHhPy4IP73rv7Oow0Ny6i70Iq0ijqj+kAtnrphlOvLFxqn6nCvQ=='
|
299 | ],
|
300 | n:
|
301 | 'v_SECtT7H4rxKtX2HpGhSyeYTe3Vet8YQpjBAr-1TnQ1fcYfvfmnVRHvhmTwABktD1erF1lxFsrRw92yBDOHlL7lj1n2fcfLftSoStgvRHVg52kR-CkBVQ6_mF1lYkefIjik6YRMf55Eu4FqDyVG2dgd5EA8kNO4J8OPc7vAtZyXrRYOZjVXbEgyjje_V-OpMQxAHP2Er11TLuzJjioP0ICVqhAZdq2sLk7agoxn64md6fqOk4N-7lJkU4-412VD0qYwKxD7nGsEclYawKoZD9_xhCk2qfQ_HptIumrdQ5ox3Sq5t2a7VKa41dBUQ1MQtXG2iY7S9RlfcMIyQwGhOQ',
|
302 | e: 'AQAB',
|
303 | kid: 'NkFCNEE1NDFDNTQ5RTQ5OTE1QzRBMjYyMzY0NEJCQTJBMjJBQkZCMA',
|
304 | x5t: 'NkFCNEE1NDFDNTQ5RTQ5OTE1QzRBMjYyMzY0NEJCQTJBMjJBQkZCMA'
|
305 | }
|
306 | ]
|
307 | });
|
308 |
|
309 | const client = new JwksClient({
|
310 | jwksUri: `${jwksHost}/.well-known/jwks.json`
|
311 | });
|
312 |
|
313 | client.getSigningKeys((err, keys) => {
|
314 | expect(err).to.be.null;
|
315 | expect(keys).not.to.be.null;
|
316 | expect(keys.length).to.equal(2);
|
317 | expect(keys[0].publicKey).not.to.be.null;
|
318 | expect(keys[0].getPublicKey()).to.equal(keys[0].publicKey);
|
319 | expect(keys[0].kid).to.equal(
|
320 | 'RkI5MjI5OUY5ODc1N0Q4QzM0OUYzNkVGMTJDOUEzQkFCOTU3NjE2Rg'
|
321 | );
|
322 | expect(keys[1].kid).to.equal(
|
323 | 'NkFCNEE1NDFDNTQ5RTQ5OTE1QzRBMjYyMzY0NEJCQTJBMjJBQkZCMA'
|
324 | );
|
325 | expect(keys[1].publicKey).not.to.be.null;
|
326 | expect(keys[1].getPublicKey()).to.equal(keys[1].publicKey);
|
327 | expect(keys[1].nbf).to.equal(123);
|
328 | done();
|
329 | });
|
330 | });
|
331 |
|
332 | it('should return signing keys (mod/exp)', done => {
|
333 | nock(jwksHost)
|
334 | .get('/.well-known/jwks.json')
|
335 | .reply(200, {
|
336 | keys: [
|
337 | {
|
338 | kid: 'IdTokenSigningKeyContainer',
|
339 | use: 'sig',
|
340 | kty: 'RSA',
|
341 | e: 'AQAB',
|
342 | n:
|
343 | 'tLDZVZ2Eq_DFwNp24yeSq_Ha0MYbYOJs_WXIgVxQGabu5cZ9561OUtYWdB6xXXZLaZxFG02P5U2rC_CT1r0lPfC_KHYrviJ5Y_Ekif7iFV_1omLAiRksQziwA1i-hND32N5kxwEGNmZViVjWMBZ43wbIdWss4IMhrJy1WNQ07Fqp1Ee6o7QM1hTBve7bbkJkUAfjtC7mwIWqZdWoYIWBTZRXvhMgs_Aeb_pnDekosqDoWQ5aMklk3NvaaBBESqlRAJZUUf5WDFoJh7yRELOFF4lWJxtArTEiQPWVTX6PCs0klVPU6SRQqrtc4kKLCp1AC5EJqPYRGiEJpSz2nUhmAQ'
|
344 | },
|
345 | {
|
346 | kid: 'IdTokenSigningKeyContainer.v2',
|
347 | nbf: 1459289287,
|
348 | use: 'sig',
|
349 | kty: 'RSA',
|
350 | e: 'AQAB',
|
351 | n:
|
352 | 's4W7xjkQZP3OwG7PfRgcYKn8eRYXHiz1iK503fS-K2FZo-Ublwwa2xFZWpsUU_jtoVCwIkaqZuo6xoKtlMYXXvfVHGuKBHEBVn8b8x_57BQWz1d0KdrNXxuMvtFe6RzMqiMqzqZrzae4UqVCkYqcR9gQx66Ehq7hPmCxJCkg7ajo7fu6E7dPd34KH2HSYRsaaEA_BcKTeb9H1XE_qEKjog68wUU9Ekfl3FBIRN-1Ah_BoktGFoXyi_jt0-L0-gKcL1BLmUlGzMusvRbjI_0-qj-mc0utGdRjY-xIN2yBj8vl4DODO-wMwfp-cqZbCd9TENyHaTb8iA27s-73L3ExOQ'
|
353 | },
|
354 | {
|
355 | kid: 'IdTokenSigningKeyContainer.v3',
|
356 | nbf: 1459289287,
|
357 | kty: 'RSA',
|
358 | e: 'AQAB',
|
359 | n:
|
360 | 's4W7xjkQZP3OwG7PfRgcYKn8eRYXHiz1iK503fS-K2FZo-Ublwwa2xFZWpsUU_jtoVCwIkaqZuo6xoKtlMYXXvfVHGuKBHEBVn8b8x_57BQWz1d0KdrNXxuMvtFe6RzMqiMqzqZrzae4UqVCkYqcR9gQx66Ehq7hPmCxJCkg7ajo7fu6E7dPd34KH2HSYRsaaEA_BcKTeb9H1XE_qEKjog68wUU9Ekfl3FBIRN-1Ah_BoktGFoXyi_jt0-L0-gKcL1BLmUlGzMusvRbjI_0-qj-mc0utGdRjY-xIN2yBj8vl4DODO-wMwfp-cqZbCd9TENyHaTb8iA27s-73L3ExOQ'
|
361 | },
|
362 | {
|
363 | kid: 'IdTokenSigningKeyContainer.v4',
|
364 | nbf: 1459289287,
|
365 | use: 'enc',
|
366 | kty: 'RSA',
|
367 | e: 'AQAB',
|
368 | n:
|
369 | 's4W7xjkQZP3OwG7PfRgcYKn8eRYXHiz1iK503fS-K2FZo-Ublwwa2xFZWpsUU_jtoVCwIkaqZuo6xoKtlMYXXvfVHGuKBHEBVn8b8x_57BQWz1d0KdrNXxuMvtFe6RzMqiMqzqZrzae4UqVCkYqcR9gQx66Ehq7hPmCxJCkg7ajo7fu6E7dPd34KH2HSYRsaaEA_BcKTeb9H1XE_qEKjog68wUU9Ekfl3FBIRN-1Ah_BoktGFoXyi_jt0-L0-gKcL1BLmUlGzMusvRbjI_0-qj-mc0utGdRjY-xIN2yBj8vl4DODO-wMwfp-cqZbCd9TENyHaTb8iA27s-73L3ExOQ'
|
370 | }
|
371 | ]
|
372 | });
|
373 |
|
374 | const client = new JwksClient({
|
375 | jwksUri: `${jwksHost}/.well-known/jwks.json`
|
376 | });
|
377 |
|
378 | client.getSigningKeys((err, keys) => {
|
379 | expect(err).to.be.null;
|
380 | expect(keys).not.to.be.null;
|
381 | expect(keys.length).to.equal(3);
|
382 | expect(keys[0].rsaPublicKey).not.to.be.null;
|
383 | expect(keys[0].getPublicKey()).to.equal(keys[0].rsaPublicKey);
|
384 | expect(keys[0].kid).to.equal('IdTokenSigningKeyContainer');
|
385 | expect(keys[1].kid).to.equal('IdTokenSigningKeyContainer.v2');
|
386 | expect(keys[1].rsaPublicKey).not.to.be.null;
|
387 | expect(keys[1].getPublicKey()).to.equal(keys[1].rsaPublicKey);
|
388 | expect(keys[1].nbf).to.equal(1459289287);
|
389 | expect(keys[2].rsaPublicKey).not.to.be.null;
|
390 | expect(keys[2].getPublicKey()).to.equal(keys[2].rsaPublicKey);
|
391 | done();
|
392 | });
|
393 | });
|
394 |
|
395 | it('should only take the signing keys from the keys', done => {
|
396 | nock(jwksHost)
|
397 | .get('/.well-known/jwks.json')
|
398 | .reply(200, {
|
399 | keys: [
|
400 | {
|
401 | kty: 'something',
|
402 | use: 'else',
|
403 | x5c: [
|
404 | 'MIIDDTCCAfWgAwIBAgIJAJVkuSv2H8mDMA0GCSqGSIb3DQEBBQUAMB0xGzAZBgNVBAMMEnNhbmRyaW5vLmF1dGgwLmNvbTAeFw0xNDA1MTQyMTIyMjZaFw0yODAxMjEyMTIyMjZaMB0xGzAZBgNVBAMMEnNhbmRyaW5vLmF1dGgwLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL6jWASkHhXz5Ug6t5BsYBrXDIgrWu05f3oq2fE+5J5REKJiY0Ddc+Kda34ZwOptnUoef3JwKPDAckTJQDugweNNZPwOmFMRKj4xqEpxEkIX8C+zHs41Q6x54ZZy0xU+WvTGcdjzyZTZ/h0iOYisswFQT/s6750tZG0BOBtZ5qS/80tmWH7xFitgewdWteJaASE/eO1qMtdNsp9fxOtN5U/pZDUyFm3YRfOcODzVqp3wOz+dcKb7cdZN11EYGZOkjEekpcedzHCo9H4aOmdKCpytqL/9FXoihcBMg39s1OW3cfwfgf5/kvOJdcqR4PoATQTfsDVoeMWVB4XLGR6SC5kCAwEAAaNQME4wHQYDVR0OBBYEFHDYn9BQdup1CoeoFi0Rmf5xn/W9MB8GA1UdIwQYMBaAFHDYn9BQdup1CoeoFi0Rmf5xn/W9MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAGLpQZdd2ICVnGjc6CYfT3VNoujKYWk7E0shGaCXFXptrZ8yaryfo6WAizTfgOpQNJH+Jz+QsCjvkRt6PBSYX/hb5OUDU2zNJN48/VOw57nzWdjI70H2Ar4oJLck36xkIRs/+QX+mSNCjZboRwh0LxanXeALHSbCgJkbzWbjVnfJEQUP9P/7NGf0MkO5I95C/Pz9g91y8gU+R3imGppLy9Zx+OwADFwKAEJak4JrNgcjHBQenakAXnXP6HG4hHH4MzO8LnLiKv8ZkKVL67da/80PcpO0miMNPaqBBMd2Cy6GzQYE0ag6k0nk+DMIFn7K+o21gjUuOEJqIbAvhbf2KcM='
|
405 | ],
|
406 | n:
|
407 | 'vqNYBKQeFfPlSDq3kGxgGtcMiCta7Tl_eirZ8T7knlEQomJjQN1z4p1rfhnA6m2dSh5_cnAo8MByRMlAO6DB401k_A6YUxEqPjGoSnESQhfwL7MezjVDrHnhlnLTFT5a9MZx2PPJlNn-HSI5iKyzAVBP-zrvnS1kbQE4G1nmpL_zS2ZYfvEWK2B7B1a14loBIT947Woy102yn1_E603lT-lkNTIWbdhF85w4PNWqnfA7P51wpvtx1k3XURgZk6SMR6Slx53McKj0fho6Z0oKnK2ov_0VeiKFwEyDf2zU5bdx_B-B_n-S84l1ypHg-gBNBN-wNWh4xZUHhcsZHpILmQ',
|
408 | e: 'AQAB',
|
409 | kid: 'RkI5MjI5OUY5ODc1N0Q4QzM0OUYzNkVGMTJDOUEzQkFCOTU3NjE2Rg',
|
410 | x5t: 'RkI5MjI5OUY5ODc1N0Q4QzM0OUYzNkVGMTJDOUEzQkFCOTU3NjE2Rg'
|
411 | },
|
412 | {
|
413 | kty: 'something',
|
414 | use: 'else',
|
415 | nbf: 123,
|
416 | x5c: [
|
417 | 'MIIDGzCCAgOgAwIBAgIJAPQM5+PwmOcPMA0GCSqGSIb3DQEBCwUAMCQxIjAgBgNVBAMMGXNhbmRyaW5vLWRldi5ldS5hdXRoMC5jb20wHhcNMTUwMzMxMDkwNTQ3WhcNMjgxMjA3MDkwNTQ3WjAkMSIwIAYDVQQDDBlzYW5kcmluby1kZXYuZXUuYXV0aDAuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv/SECtT7H4rxKtX2HpGhSyeYTe3Vet8YQpjBAr+1TnQ1fcYfvfmnVRHvhmTwABktD1erF1lxFsrRw92yBDOHlL7lj1n2fcfLftSoStgvRHVg52kR+CkBVQ6/mF1lYkefIjik6YRMf55Eu4FqDyVG2dgd5EA8kNO4J8OPc7vAtZyXrRYOZjVXbEgyjje/V+OpMQxAHP2Er11TLuzJjioP0ICVqhAZdq2sLk7agoxn64md6fqOk4N+7lJkU4+412VD0qYwKxD7nGsEclYawKoZD9/xhCk2qfQ/HptIumrdQ5ox3Sq5t2a7VKa41dBUQ1MQtXG2iY7S9RlfcMIyQwGhOQIDAQABo1AwTjAdBgNVHQ4EFgQUHpS1fvO/54G2c1VpEDNUZRSl44gwHwYDVR0jBBgwFoAUHpS1fvO/54G2c1VpEDNUZRSl44gwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAtm9I0nr6eXF5aq4yllfiqZcQ6mKrJLH9Rm4Jv+olniNynTcnpwprRVLToIawc8MmzIGZTtCn7u+dSxWf1UNE+SH7XgEnGtO74239vleEx1+Tf5viIdsnCxgvFiPdOqRlc9KcFSWd6a7RzcglnyU7GEx0K5GLv1wPA6qEM+3uwNwjAyVSu5dFw8kCfaSvlk5rXKRUzSoW9NVomw6+tADR8vMZS+4KThZ+4GH0rMN4KjIaRFxW8OMVYOn12uq33fLCd6MuPHW/rklxLbQBoHIU/ClNhbD0t6f00w9lHhPy4IP73rv7Oow0Ny6i70Iq0ijqj+kAtnrphlOvLFxqn6nCvQ=='
|
418 | ],
|
419 | n:
|
420 | 'v_SECtT7H4rxKtX2HpGhSyeYTe3Vet8YQpjBAr-1TnQ1fcYfvfmnVRHvhmTwABktD1erF1lxFsrRw92yBDOHlL7lj1n2fcfLftSoStgvRHVg52kR-CkBVQ6_mF1lYkefIjik6YRMf55Eu4FqDyVG2dgd5EA8kNO4J8OPc7vAtZyXrRYOZjVXbEgyjje_V-OpMQxAHP2Er11TLuzJjioP0ICVqhAZdq2sLk7agoxn64md6fqOk4N-7lJkU4-412VD0qYwKxD7nGsEclYawKoZD9_xhCk2qfQ_HptIumrdQ5ox3Sq5t2a7VKa41dBUQ1MQtXG2iY7S9RlfcMIyQwGhOQ',
|
421 | e: 'AQAB',
|
422 | kid: 'NkFCNEE1NDFDNTQ5RTQ5OTE1QzRBMjYyMzY0NEJCQTJBMjJBQkZCMA',
|
423 | x5t: 'NkFCNEE1NDFDNTQ5RTQ5OTE1QzRBMjYyMzY0NEJCQTJBMjJBQkZCMA'
|
424 | }
|
425 | ]
|
426 | });
|
427 |
|
428 | const client = new JwksClient({
|
429 | jwksUri: `${jwksHost}/.well-known/jwks.json`
|
430 | });
|
431 |
|
432 | client.getSigningKeys(err => {
|
433 | expect(err).not.to.be.null;
|
434 | expect(err.name).to.equal('JwksError');
|
435 | expect(err.message).to.equal(
|
436 | 'The JWKS endpoint did not contain any signing keys'
|
437 | );
|
438 | done();
|
439 | });
|
440 | });
|
441 | });
|
442 |
|
443 | describe('#getSigningKey', () => {
|
444 | it('should return error if signing key is not found', done => {
|
445 | nock(jwksHost)
|
446 | .get('/.well-known/jwks.json')
|
447 | .reply(200, x5cMultiple);
|
448 |
|
449 | const client = new JwksClient({
|
450 | jwksUri: `${jwksHost}/.well-known/jwks.json`
|
451 | });
|
452 |
|
453 | client.getSigningKey('1234', err => {
|
454 | expect(err).not.to.be.null;
|
455 | expect(err.name).to.equal('SigningKeyNotFoundError');
|
456 | done();
|
457 | });
|
458 | });
|
459 | });
|
460 | });
|