UNPKG

47.1 kBJavaScriptView Raw
1// Generated by CoffeeScript 1.10.0
2;(function () {
3 var AccessToken, AnvilConnect, IDToken, chai, cwd, expect, nock, path, sinon, sinonChai
4
5 cwd = process.cwd()
6 path = require('path')
7 chai = require('chai')
8 sinon = require('sinon')
9 sinonChai = require('sinon-chai')
10 expect = chai.expect
11 nock = require('nock')
12
13 chai.use(sinonChai)
14 chai.should()
15
16 AnvilConnect = require(path.join(cwd, 'index'))
17 AccessToken = require(path.join(cwd, 'lib', 'AccessToken'))
18 IDToken = require(path.join(cwd, 'lib', 'IDToken'))
19
20 describe('Anvil Connect Client', function () {
21 // {anvil,promise,success,failure} = {}
22 var anvil = {}
23 var failure = {}
24 var promise = {}
25 var success = {}
26 var config = {
27 issuer: 'https://connect.anvil.io',
28 client_id: 'uuid',
29 client_secret: 'secret',
30 redirect_uri: 'https://app.example.com/callback'
31 }
32 var openid = {
33 'issuer': 'https://connect.anvil.io',
34 'authorization_endpoint': 'https://connect.anvil.io/authorize',
35 'token_endpoint': 'https://connect.anvil.io/token',
36 'userinfo_endpoint': 'https://connect.anvil.io/userinfo',
37 'jwks_uri': 'https://connect.anvil.io/jwks',
38 'registration_endpoint': 'https://connect.anvil.io/register',
39 'scopes_supported': ['realm', 'client', 'profile', 'openid'],
40 'response_types_supported': ['code', 'token id_token'],
41 'response_modes_supported': [],
42 'grant_types_supported': ['authorization_code', 'refresh_token'],
43 'acr_values_supported': [],
44 'subject_types_supported': ['public'],
45 'id_token_signing_alg_values_supported': ['RS256'],
46 'id_token_encryption_alg_values_supported': [],
47 'id_token_encryption_enc_values_supported': [],
48 'userinfo_signing_alg_values_supported': ['none'],
49 'userinfo_encryption_alg_values_supported': [],
50 'userinfo_encryption_enc_values_supported': [],
51 'request_object_signing_alg_values_supported': [],
52 'request_object_encryption_alg_values_supported': [],
53 'request_object_encryption_enc_values_supported': [],
54 'token_endpoint_auth_methods_supported': ['client_secret_basic', 'client_secret_post'],
55 'token_endpoint_auth_signing_alg_values_supported': [],
56 'display_values_supported': [],
57 'claim_types_supported': ['normal'],
58 'claims_supported': ['iss', 'sub', 'aud', 'acr', 'name', 'given_name', 'family_name', 'middle_name', 'nickname', 'preferred_username', 'profile', 'picture', 'website', 'email', 'email_verified', 'zoneinfo', 'locale', 'joined_at', 'updated_at'],
59 'service_documentation': 'https://anvil.io/docs/connect/',
60 'claims_locales_supported': [],
61 'ui_locales_supported': [],
62 'check_session_iframe': 'https://connect.anvil.io/session',
63 'end_session_endpoint': 'https://connect.anvil.io/signout'
64 }
65 var jwks = {
66 'keys': [
67 {
68 'kty': 'RSA',
69 'use': 'sig',
70 'alg': 'RS256',
71 'n': 'zRchTwN0Ok6suWzaWYsbfZ81qdGVZM_LCqR6dhtlHaYAPpyVKefY3U5ByhbvDgbCm3BQ9OLu1E4OEJFkJVYvapxsyosrnSyY7qjLxHGKC-16AQNhX8qssTZVQCzdnKk67RUyKraM87zPkWNU6Qlw539-O9-g54YICKZV7ESfvA4nVvHQTJr8mem6S0GrRHxma8gEecogAvQCw5c2Hb500lW8eGqQ8qFjiBPQVScf4PZul4UO01KFB-cKiK575bFpxLSgfFBIGvqbjRgxLGkJnYq6IhtRfPQ0LAcM8rjYIINcFtLv9P647JcjrwNrxjP-yG_C84UddJl9L5kdA4_8JHom1sfaR7izF2B2mBFrGNODYDj8LctmWi4FaXBAIKa8XNW9lGv6Olc6G9AHpjzcQOY_lwAYWmULsotRRWfuV7wr49CyMSnthcd2smoA7ABed7qfd4FDCIft4SpONu7Mfba-pf8-0yYbXUcCdQzgaFr4P7MzMre4tcMhmWa89tMDP-XklptjgBmmK7RNdqk_g_Ol2KSXb233bIVd3tL8VgO1_vxwrvSZr_k9169GlsB3Ud50ulG_b6MOQxbpKZb1WEP_ajaZ8RnQOAFvfBKxBBxxT6y0maNtRGtpunYWmkxBPs-eJKZrYpVGLSX0ZwPOoPpQDInOuPcAuCp2Y3sEXK8',
72 'e': 'AQAB'
73 }, {
74 'kty': 'RSA',
75 'use': 'enc',
76 'alg': 'RS256',
77 'n': 'xoAIJ40-f5lr07WswyF6XryOtEJSpNYY_RFmMdKWMLoZnZ4dTl9LlBFyXYNunbkKQHXmhTTr_C6FWjUA6JZwCkymtgD5Be8Mz8N8K0RB6nokLzXzUilYrY8m_0G1yLAGAeAv0evGXMJN5GLuHzInB9zPzySr7xsCUB0L5DuEv6WJ4abNw5ylnLKLW9nvGfZDXwJ4YVJOaVre3S8CjvXu1fuTmzBW3VSD9Zttd_NB6uiS0QsvFBifHx-S1PZ_LZNGC52Z3-rs9kMzzneBiBJrhULFsyGF5OQBGBDQD5Ghl_O86DyCXKOGrIDso2l7ZY5vlicL9QD7jeBJnIF9sDnZDugoVneT2yHMBqiDKlFHKjGSE_mKhnD1K-QMolOwbADNytMeu5BDgFYdAkx9hyo1L2f8f4eB7_8XUSCnnQoIR9tb5ie9bSpd4Uel881N97WLVe9hyUVY0YSU3MKHaoNrPYVbGYjRsQrK14-NaZ3bC4Grrwd8eGGFaQeT_a4dIFfBfHtl_wH-DGZIqlTLX9fxfeNu93I4zPky1TlQaTwFiRo-9FXF6I6r2s2WaZKLnFWKdS2c0VrHJQebrkAN0VQNhp9-7jBRQqJmTiNVSg7J5wd7mgCMXIOfktOBHoNiulMRd9rYN21qRxt0xOwFujNZ8mlx2M96gBdhDVq020zJdB0',
78 'e': 'AQAB'
79 }
80 ]
81 }
82 var registration = {
83 client_name: 'TEST CLIENT',
84 redirect_uris: ['http://app.example.com/callback']
85 }
86 var registrationResponse = {
87 client_id: 'a011bbd4-6171-4d84-ba1a-7db73fd64056',
88 client_secret: 'cd38a23c7a53045cbb64',
89 client_name: registration.client_name,
90 token_endpoint_auth_method: 'client_secret_basic',
91 application_type: 'web',
92 redirect_uris: registration.redirect_uris,
93 client_id_issued_at: 1441564333989
94 }
95 var userinfo = {
96 given_name: 'FAKE',
97 family_name: 'USER'
98 }
99 describe('constructor', function () {
100 before(function () {
101 anvil = new AnvilConnect(config)
102 })
103 it('should set the issuer', function () {
104 return anvil.issuer.should.equal(config.issuer)
105 })
106 it('should set the client id', function () {
107 return anvil.client_id.should.equal(config.client_id)
108 })
109 it('should set the client secret', function () {
110 return anvil.client_secret.should.equal(config.client_secret)
111 })
112 it('should set the redirect uri', function () {
113 anvil.redirect_uri = config.redirect_uri
114 return anvil.redirect_uri
115 })
116 it('should set default scope', function () {
117 return anvil.scope.should.equal('openid profile')
118 })
119 it('should set scope from an array', function () {
120 anvil = new AnvilConnect({
121 scope: ['realm']
122 })
123 return anvil.scope.should.contain('realm')
124 })
125 return it('should set scope from a string', function () {
126 anvil = new AnvilConnect({
127 scope: 'realm extra'
128 })
129 anvil.scope.should.contain('realm')
130 return anvil.scope.should.contain('extra')
131 })
132 })
133 describe('discover', function () {
134 describe('with a successful response', function () {
135 beforeEach(function (done) {
136 anvil = new AnvilConnect(config)
137 nock(anvil.issuer).get('/.well-known/openid-configuration').reply(200, openid)
138 success = sinon.spy(function () {
139 return done()
140 })
141 failure = sinon.spy(function () {
142 return done()
143 })
144 promise = anvil.discover().then(success)['catch'](failure)
145 return promise
146 })
147 after(function () {
148 return nock.cleanAll()
149 })
150 it('should return a promise', function () {
151 return promise.should.be['instanceof'](Promise)
152 })
153 it('should provide the openid configuration', function () {
154 return success.should.have.been.calledWith(sinon.match({
155 issuer: anvil.issuer
156 }))
157 })
158 it('should set configuration', function () {
159 return anvil.configuration.should.eql(openid)
160 })
161 return it('should not catch an error', function () {
162 return failure.should.not.have.been.called
163 })
164 })
165 describe('with a failure response', function () {
166 beforeEach(function (done) {
167 // var data = {
168 // issuer: anvil.issuer
169 // }
170 anvil = new AnvilConnect(config)
171 nock(anvil.issuer)
172 .get('/.well-known/openid-configuration')
173 .reply(404, 'Not found')
174 success = sinon.spy(function () {
175 return done()
176 })
177 failure = sinon.spy(function () {
178 return done()
179 })
180 promise = anvil.discover().then(success)['catch'](failure)
181 return promise
182 })
183 after(function () {
184 return nock.cleanAll()
185 })
186 it('should return a promise', function () {
187 return promise.should.be['instanceof'](Promise)
188 })
189 it('should not provide the openid configuration', function () {
190 return success.should.not.have.been.called
191 })
192 it('should not set configuration', function () {
193 return expect(anvil.configuration).to.be.undefined
194 })
195 return it('should not catch an error', function () {
196 return failure.should.have.been.called
197 })
198 })
199 return describe('with an invalid response', function () {
200 beforeEach(function (done) {
201 // var data = {
202 // issuer: anvil.issuer
203 // }
204 anvil = new AnvilConnect(config)
205 nock(anvil.issuer).get('/.well-known/openid-configuration').reply(200, "This isn't JSON!")
206 success = sinon.spy(function () {
207 return done()
208 })
209 failure = sinon.spy(function () {
210 return done()
211 })
212 promise = anvil.discover().then(success)['catch'](failure)
213 return promise
214 })
215 after(function () {
216 return nock.cleanAll()
217 })
218 it('should return a promise', function () {
219 return promise.should.be['instanceof'](Promise)
220 })
221 it('should not provide the openid configuration', function () {
222 return success.should.not.have.been.called
223 })
224 it('should not set configuration', function () {
225 return expect(anvil.configuration).to.be.undefined
226 })
227 return it('should not catch an error', function () {
228 return failure.should.have.been.called
229 })
230 })
231 })
232 describe('jwks', function () {
233 describe('with a successful response', function () {
234 beforeEach(function (done) {
235 anvil = new AnvilConnect(config)
236 anvil.configuration = openid
237 nock(anvil.issuer).get('/jwks').reply(200, jwks)
238 success = sinon.spy(function () {
239 return done()
240 })
241 failure = sinon.spy(function () {
242 return done()
243 })
244 promise = anvil.getJWKs().then(success)['catch'](failure)
245 return promise
246 })
247 after(function () {
248 return nock.cleanAll()
249 })
250 it('should return a promise', function () {
251 return promise.should.be['instanceof'](Promise)
252 })
253 it('should provide the JWK set', function () {
254 return success.should.have.been.calledWith(sinon.match(jwks))
255 })
256 it('should set jwks', function () {
257 return anvil.jwks.keys.should.eql(jwks.keys)
258 })
259 it('should set signature jwk', function () {
260 return anvil.jwks.sig.should.eql(jwks.keys[0])
261 })
262 return it('should not catch an error', function () {
263 return failure.should.not.have.been.called
264 })
265 })
266 return describe('with a failure response', function () {
267 beforeEach(function (done) {
268 anvil = new AnvilConnect(config)
269 anvil.configuration = openid
270 nock(anvil.issuer).get('/jwks').reply(404, 'Not found')
271 success = sinon.spy(function () {
272 return done()
273 })
274 failure = sinon.spy(function () {
275 return done()
276 })
277 promise = anvil.getJWKs().then(success)['catch'](failure)
278 return promise
279 })
280 after(function () {
281 return nock.cleanAll()
282 })
283 it('should return a promise', function () {
284 return promise.should.be['instanceof'](Promise)
285 })
286 it('should not provide the JWK set', function () {
287 return success.should.not.have.been.called
288 })
289 it('should not set jwks', function () {
290 return expect(anvil.jwks).to.be.undefined
291 })
292 return it('should catch an error', function () {
293 return failure.should.have.been.called
294 })
295 })
296 })
297 describe('register', function () {
298 describe('with a successful response', function () {
299 beforeEach(function (done) {
300 anvil = new AnvilConnect(config)
301 anvil.configuration = openid
302 nock(anvil.issuer).post('/register', registration).reply(201, registrationResponse)
303 success = sinon.spy(function () {
304 return done()
305 })
306 failure = sinon.spy(function () {
307 return done()
308 })
309 promise = anvil.register(registration).then(success)['catch'](failure)
310 return promise
311 })
312 after(function () {
313 return nock.cleanAll()
314 })
315 it('should return a promise', function () {
316 return promise.should.be['instanceof'](Promise)
317 })
318 it('should provide the registration response', function () {
319 return success.should.have.been.calledWith(sinon.match(registrationResponse))
320 })
321 return it('should not catch an error', function () {
322 return failure.should.not.have.been.called
323 })
324 })
325 return describe('with a failure response', function () {
326 beforeEach(function (done) {
327 anvil = new AnvilConnect(config)
328 anvil.configuration = openid
329 nock(anvil.issuer).post('/register', registration).reply(400, {
330 error: 'whatever'
331 })
332 success = sinon.spy(function () {
333 return done()
334 })
335 failure = sinon.spy(function () {
336 return done()
337 })
338 promise = anvil.register(registration).then(success)['catch'](failure)
339 return promise
340 })
341 after(function () {
342 return nock.cleanAll()
343 })
344 it('should return a promise', function () {
345 return promise.should.be['instanceof'](Promise)
346 })
347 it('should not provide the registration response', function () {
348 return success.should.have.not.been.called
349 })
350 return it('should catch an error', function () {
351 return failure.should.have.been.called
352 })
353 })
354 })
355 describe('authorizationUri', function () {
356 beforeEach(function () {
357 anvil = new AnvilConnect(config)
358 anvil.configuration = openid
359 })
360 describe('with no endpoint in the argument', function () {
361 return it('should use the "authorize" endpoint', function () {
362 return anvil.authorizationUri().should.contain('/authorize?')
363 })
364 })
365 describe('with a string argument', function () {
366 return it('should use the argument as the endpoint', function () {
367 return anvil.authorizationUri('signin').should.contain('/signin?')
368 })
369 })
370 return describe('with an options argument', function () {
371 it('should set the optional endpoint', function () {
372 var uri
373 uri = anvil.authorizationUri({
374 endpoint: 'connect/google'
375 })
376 return uri.should.contain('/connect/google?')
377 })
378 it('should set default authorization params', function () {
379 var uri
380 uri = anvil.authorizationUri({
381 endpoint: 'connect/google'
382 })
383 uri.should.contain('response_type=code')
384 uri.should.contain('client_id=' + config.client_id)
385 uri.should.contain('redirect_uri=' + (encodeURIComponent(config.redirect_uri)))
386 return uri.should.contain('scope=' + (encodeURIComponent(anvil.scope)))
387 })
388 return it('should set optional authorization params', function () {
389 var uri
390 uri = anvil.authorizationUri({
391 endpoint: 'signin',
392 provider: 'password',
393 max_age: 2600
394 })
395 uri.should.contain('provider=password')
396 return uri.should.contain('max_age=2600')
397 })
398 })
399 })
400 describe('authorizationParams', function () {
401 beforeEach(function () {
402 anvil = new AnvilConnect(config)
403 anvil.configuration = openid
404 })
405 it('should set default response type', function () {
406 return anvil.authorizationParams().response_type.should.equal('code')
407 })
408 it('should set optional response type', function () {
409 return anvil.authorizationParams({
410 response_type: 'id_token token'
411 }).response_type.should.equal('id_token token')
412 })
413 it('should set client id', function () {
414 return anvil.authorizationParams().client_id.should.equal(config.client_id)
415 })
416 it('should set configured redirect uri', function () {
417 return anvil.authorizationParams().redirect_uri.should.equal(config.redirect_uri)
418 })
419 it('should set optional redirect uri', function () {
420 var uri
421 uri = 'https://app.example.com/other'
422 return anvil.authorizationParams({
423 redirect_uri: uri
424 }).redirect_uri.should.equal(uri)
425 })
426 it('should set configured scope', function () {
427 return anvil.authorizationParams().scope.should.equal(anvil.scope)
428 })
429 it('should set optional scope', function () {
430 return anvil.authorizationParams({
431 scope: 'foo bar'
432 }).scope.should.equal('foo bar')
433 })
434 it('should set optional parameters', function () {
435 return anvil.authorizationParams({
436 prompt: 'none'
437 }).prompt.should.equal('none')
438 })
439 return it('should ignore unknown parameters', function () {
440 var params
441 params = anvil.authorizationParams({
442 unknown: 'forgetme'
443 })
444 return expect(params.unknown).to.be.undefined
445 })
446 })
447 describe('refresh', function () {
448 describe('with missing options argument', function () {
449 beforeEach(function (done) {
450 anvil = new AnvilConnect(config)
451 anvil.configuration = openid
452 success = sinon.spy(function () {
453 return done()
454 })
455 failure = sinon.spy(function () {
456 return done()
457 })
458 promise = anvil.refresh().then(success)['catch'](failure)
459 return promise
460 })
461 it('should return a promise', function () {
462 return promise.should.be['instanceof'](Promise)
463 })
464 it('should not provide the tokens', function () {
465 return success.should.not.have.been.called
466 })
467 return it('should catch an error', function () {
468 return failure.should.have.been.calledWith(sinon.match({
469 message: 'Missing refresh_token'
470 }))
471 })
472 })
473 describe('with error response', function () {
474 beforeEach(function (done) {
475 anvil = new AnvilConnect(config)
476 anvil.configuration = openid
477 nock(anvil.issuer).post('/token', {
478 grant_type: 'refresh_token',
479 refresh_token: 'random'
480 }).basicAuth({
481 user: config.client_id,
482 pass: config.client_secret
483 }).reply(400, {
484 error: 'invalid_request'
485 })
486 success = sinon.spy(function () {
487 return done()
488 })
489 failure = sinon.spy(function () {
490 return done()
491 })
492 promise = anvil.refresh({
493 refresh_token: 'random'
494 }).then(success)['catch'](failure)
495 return promise
496 })
497 after(function () {
498 return nock.cleanAll()
499 })
500 it('should return a promise', function () {
501 return promise.should.be['instanceof'](Promise)
502 })
503 it('should not provide the tokens', function () {
504 return success.should.not.have.been.called
505 })
506 return it('should catch an error', function () {
507 return failure.should.have.been.called
508 })
509 })
510 describe('with token response and signature ko', function () {
511 beforeEach(function (done) {
512 anvil = new AnvilConnect(config)
513 anvil.configuration = openid
514 anvil.jwks = jwks
515 anvil.tokens = {
516 access_token: 'jwt1',
517 id_token: 'jwt2'
518 }
519 nock(anvil.issuer).post('/token', {
520 grant_type: 'refresh_token',
521 refresh_token: 'fake_refresh_token'
522 }).basicAuth({
523 user: config.client_id,
524 pass: config.client_secret
525 }).reply(200, anvil.tokens)
526 sinon.stub(AccessToken, 'refresh').callsArgWith(2, null, anvil.tokens)
527 sinon.stub(AccessToken, 'verify').callsArgWith(2, new Error(), null)
528 success = sinon.spy(function () {
529 return done()
530 })
531 failure = sinon.spy(function () {
532 return done()
533 })
534 promise = anvil.refresh({
535 refresh_token: 'fake_refresh_token'
536 }).then(success)['catch'](failure)
537 return promise
538 })
539 after(function () {
540 return nock.cleanAll()
541 })
542 afterEach(function () {
543 AccessToken.refresh.restore()
544 return AccessToken.verify.restore()
545 })
546 it('should return a promise', function () {
547 return promise.should.be['instanceof'](Promise)
548 })
549 it('should not provide the tokens', function () {
550 return success.should.not.have.been.called
551 })
552 it('should catch an error', function () {
553 return failure.should.have.been.called
554 })
555 it('should AccessToken.refresh called once', function () {
556 return AccessToken.refresh.should.have.been.calledOnce
557 })
558 return it('should AccessToken.verify called once', function () {
559 return AccessToken.verify.should.have.been.calledOnce
560 })
561 })
562 return describe('with token response and signature ok', function () {
563 beforeEach(function (done) {
564 anvil = new AnvilConnect(config)
565 anvil.configuration = openid
566 anvil.jwks = jwks
567 anvil.jwks.keys[0] = jwks.keys[0]
568 anvil.tokens = {
569 access_token: 'jwt1',
570 id_token: 'jwt2'
571 }
572 nock(anvil.issuer).post('/token', {
573 grant_type: 'refresh_token',
574 refresh_token: 'fake_refresh_token'
575 }).basicAuth({
576 user: config.client_id,
577 pass: config.client_secret
578 }).reply(200, anvil.tokens)
579 sinon.stub(AccessToken, 'refresh').callsArgWith(2, null, anvil.tokens)
580 sinon.stub(AccessToken, 'verify').callsArgWith(2, null, anvil.tokens)
581 success = sinon.spy(function () {
582 return done()
583 })
584 failure = sinon.spy(function () {
585 return done()
586 })
587 promise = anvil.refresh({
588 refresh_token: 'fake_refresh_token'
589 }).then(success)['catch'](failure)
590 return promise
591 })
592 after(function () {
593 return nock.cleanAll()
594 })
595 afterEach(function () {
596 AccessToken.refresh.restore()
597 return AccessToken.verify.restore()
598 })
599 it('should return a promise', function () {
600 return promise.should.be['instanceof'](Promise)
601 })
602 it('should provide the tokens', function () {
603 return success.should.have.been.called
604 })
605 it('should not catch an error', function () {
606 return failure.should.not.have.been.called
607 })
608 it('should AccessToken.refresh called once', function () {
609 return AccessToken.refresh.should.have.been.calledOnce
610 })
611 it('should AccessToken.verify called once', function () {
612 return AccessToken.verify.should.have.been.calledOnce
613 })
614 return it('should provide the tokens', function () {
615 return success.should.have.been.calledWith(sinon.match(anvil.tokens))
616 })
617 })
618 })
619 describe('token', function () {
620 describe('with missing options argument', function () {
621 beforeEach(function (done) {
622 anvil = new AnvilConnect(config)
623 anvil.configuration = openid
624 success = sinon.spy(function () {
625 return done()
626 })
627 failure = sinon.spy(function () {
628 return done()
629 })
630 promise = anvil.token().then(success)['catch'](failure)
631 return promise
632 })
633 it('should return a promise', function () {
634 return promise.should.be['instanceof'](Promise)
635 })
636 it('should not provide the tokens', function () {
637 return success.should.not.have.been.called
638 })
639 return it('should catch an error', function () {
640 return failure.should.have.been.calledWith(sinon.match({
641 message: 'Missing authorization code'
642 }))
643 })
644 })
645 describe('with missing authorization code', function () {
646 beforeEach(function (done) {
647 anvil = new AnvilConnect(config)
648 anvil.configuration = openid
649 success = sinon.spy(function () {
650 return done()
651 })
652 failure = sinon.spy(function () {
653 return done()
654 })
655 promise = anvil.token({}).then(success)['catch'](failure)
656 return promise
657 })
658 it('should return a promise', function () {
659 return promise.should.be['instanceof'](Promise)
660 })
661 it('should not provide the tokens', function () {
662 return success.should.not.have.been.called
663 })
664 return it('should catch an error', function () {
665 return failure.should.have.been.calledWith(sinon.match({
666 message: 'Missing authorization code'
667 }))
668 })
669 })
670 describe('with error response', function () {
671 beforeEach(function (done) {
672 anvil = new AnvilConnect(config)
673 anvil.configuration = openid
674 anvil.tokens = {
675 access_token: 'jwt1',
676 id_token: 'jwt2'
677 }
678 nock(anvil.issuer).post('/token', {
679 grant_type: 'authorization_code',
680 code: 'random',
681 redirect_uri: config.redirect_uri
682 }).basicAuth({
683 user: config.client_id,
684 pass: config.client_secret
685 }).reply(400, {
686 error: 'invalid_request'
687 })
688 success = sinon.spy(function () {
689 return done()
690 })
691 failure = sinon.spy(function () {
692 return done()
693 })
694 promise = anvil.token({
695 code: 'random'
696 }).then(success)['catch'](failure)
697 return promise
698 })
699 after(function () {
700 return nock.cleanAll()
701 })
702 it('should return a promise', function () {
703 return promise.should.be['instanceof'](Promise)
704 })
705 it('should not provide the tokens', function () {
706 return success.should.not.have.been.called
707 })
708 return it('should catch an error', function () {
709 return failure.should.have.been.called
710 })
711 })
712 describe('with unverifiable id token', function () {
713 var tokens
714 tokens = {}.tokens
715 before(function (done) {
716 // var claims = {
717 // sub: 'uuid'
718 // }
719 anvil = new AnvilConnect(config)
720 anvil.configuration = openid
721 anvil.jwks = jwks
722 anvil.jwks.sig = jwks.keys[0]
723 tokens = {
724 id_token: 'invalid.id.token',
725 access_token: 'valid.access.token'
726 }
727 nock(anvil.issuer).post('/token', {
728 grant_type: 'authorization_code',
729 code: 'random',
730 redirect_uri: config.redirect_uri
731 }).basicAuth({
732 user: config.client_id,
733 pass: config.client_secret
734 }).reply(200, tokens)
735 sinon.stub(IDToken, 'verify').callsArgWith(2, new Error())
736 sinon.stub(AccessToken, 'verify').callsArgWith(2, null, {})
737 success = sinon.spy(function () {
738 return done()
739 })
740 failure = sinon.spy(function () {
741 return done()
742 })
743 promise = anvil.token({
744 code: 'random'
745 }).then(success)['catch'](failure)
746 return promise
747 })
748 after(function () {
749 IDToken.verify.restore()
750 AccessToken.verify.restore()
751 return nock.cleanAll()
752 })
753 it('should return a promise', function () {
754 return promise.should.be['instanceof'](Promise)
755 })
756 it('should verify the id token', function () {
757 return IDToken.verify.should.have.been.calledWith(tokens.id_token)
758 })
759 it('should verify the access token', function () {
760 return AccessToken.verify.should.have.been.calledWith(tokens.access_token)
761 })
762 it('should not provide the id claims', function () {
763 return success.should.not.have.been.called
764 })
765 return it('should not catch an error', function () {
766 return failure.should.have.been.called
767 })
768 })
769 describe('with unverifiable access token', function () {
770 var tokens
771 tokens = {}.tokens
772 before(function (done) {
773 // var claims = {
774 // sub: 'uuid'
775 // }
776 anvil = new AnvilConnect(config)
777 anvil.configuration = openid
778 anvil.jwks = jwks
779 anvil.jwks.sig = jwks.keys[0]
780 tokens = {
781 id_token: 'valid.id.token',
782 access_token: 'invalid.access.token'
783 }
784 nock(anvil.issuer).post('/token', {
785 grant_type: 'authorization_code',
786 code: 'random',
787 redirect_uri: config.redirect_uri
788 }).basicAuth({
789 user: config.client_id,
790 pass: config.client_secret
791 }).reply(200, tokens)
792 sinon.stub(AccessToken, 'verify').callsArgWith(2, new Error())
793 sinon.stub(IDToken, 'verify').callsArgWith(2, null, {})
794 success = sinon.spy(function () {
795 return done()
796 })
797 failure = sinon.spy(function () {
798 return done()
799 })
800 promise = anvil.token({
801 code: 'random'
802 }).then(success)['catch'](failure)
803 return promise
804 })
805 after(function () {
806 AccessToken.verify.restore()
807 IDToken.verify.restore()
808 return nock.cleanAll()
809 })
810 it('should return a promise', function () {
811 return promise.should.be['instanceof'](Promise)
812 })
813 it('should verify the id token', function () {
814 return IDToken.verify.should.have.been.calledWith(tokens.id_token)
815 })
816 it('should verify the access token', function () {
817 return AccessToken.verify.should.have.been.calledWith(tokens.access_token)
818 })
819 it('should not provide the id claims', function () {
820 return success.should.not.have.been.called
821 })
822 return it('should not catch an error', function () {
823 return failure.should.have.been.called
824 })
825 })
826 describe('with valid token response', function () {
827 var tokens
828 tokens = {}.tokens
829 beforeEach(function (done) {
830 anvil = new AnvilConnect(config)
831 anvil.configuration = openid
832 anvil.jwks = jwks
833 anvil.jwks.sig = jwks.keys[0]
834 tokens = {
835 id_token: 'valid.id.token',
836 access_token: 'valid.access.token'
837 }
838 nock(anvil.issuer).post('/token', {
839 grant_type: 'authorization_code',
840 code: 'random',
841 redirect_uri: config.redirect_uri
842 }).basicAuth({
843 user: config.client_id,
844 pass: config.client_secret
845 }).reply(200, tokens)
846 sinon.stub(AccessToken, 'verify').callsArgWith(2, null, {
847 aud: config.client_id
848 })
849 sinon.stub(IDToken, 'verify').callsArgWith(2, null, {
850 payload: {
851 iss: config.issuer
852 }
853 })
854 success = sinon.spy(function () {
855 return done()
856 })
857 failure = sinon.spy(function () {
858 return done()
859 })
860 promise = anvil.token({
861 code: 'random'
862 }).then(success)['catch'](failure)
863 return promise
864 })
865 afterEach(function () {
866 AccessToken.verify.restore()
867 IDToken.verify.restore()
868 return nock.cleanAll()
869 })
870 it('should return a promise', function () {
871 return promise.should.be['instanceof'](Promise)
872 })
873 it('should verify the id token', function () {
874 return IDToken.verify.should.have.been.calledWith(tokens.id_token)
875 })
876 it('should verify the access token', function () {
877 return AccessToken.verify.should.have.been.calledWith(tokens.access_token)
878 })
879 it('should provide the tokens', function () {
880 return success.should.have.been.calledWith(sinon.match(tokens))
881 })
882 it('should provide the id claims', function () {
883 return success.should.have.been.calledWith(sinon.match({
884 id_claims: {
885 iss: config.issuer
886 }
887 }))
888 })
889 it('should provide the access claims', function () {
890 return success.should.have.been.calledWith(sinon.match({
891 access_claims: {
892 aud: config.client_id
893 }
894 }))
895 })
896 return it('should not catch an error', function () {
897 return failure.should.not.have.been.called
898 })
899 })
900 describe('with response uri', function () {
901 var tokens
902 tokens = {}.tokens
903 beforeEach(function (done) {
904 anvil = new AnvilConnect(config)
905 anvil.configuration = openid
906 anvil.jwks = jwks
907 anvil.jwks.sig = jwks.keys[0]
908 tokens = {
909 id_token: 'valid.id.token',
910 access_token: 'valid.access.token'
911 }
912 nock(anvil.issuer).post('/token', {
913 grant_type: 'authorization_code',
914 code: 'random',
915 redirect_uri: config.redirect_uri
916 }).basicAuth({
917 user: config.client_id,
918 pass: config.client_secret
919 }).reply(200, tokens)
920 sinon.stub(AccessToken, 'verify').callsArgWith(2, null, {
921 aud: config.client_id
922 })
923 sinon.stub(IDToken, 'verify').callsArgWith(2, null, {
924 payload: {
925 iss: config.issuer
926 }
927 })
928 success = sinon.spy(function () {
929 return done()
930 })
931 failure = sinon.spy(function (err) {
932 console.log(err)
933 return done()
934 })
935 promise = anvil.token({
936 responseUri: 'https://app.example.com/callback?code=random'
937 }).then(success)['catch'](failure)
938 return promise
939 })
940 afterEach(function () {
941 AccessToken.verify.restore()
942 IDToken.verify.restore()
943 return nock.cleanAll()
944 })
945 it('should return a promise', function () {
946 return promise.should.be['instanceof'](Promise)
947 })
948 it('should verify the id token', function () {
949 return IDToken.verify.should.have.been.calledWith(tokens.id_token)
950 })
951 it('should verify the access token', function () {
952 return AccessToken.verify.should.have.been.calledWith(tokens.access_token)
953 })
954 it('should provide the tokens', function () {
955 return success.should.have.been.calledWith(sinon.match(tokens))
956 })
957 it('should provide the id claims', function () {
958 return success.should.have.been.calledWith(sinon.match({
959 id_claims: {
960 iss: config.issuer
961 }
962 }))
963 })
964 it('should provide the access claims', function () {
965 return success.should.have.been.calledWith(sinon.match({
966 access_claims: {
967 aud: config.client_id
968 }
969 }))
970 })
971 return it('should not catch an error', function () {
972 return failure.should.not.have.been.called
973 })
974 })
975 return describe('with client_credentials grant', function () {
976 var tokens
977 tokens = {}.tokens
978 beforeEach(function (done) {
979 anvil = new AnvilConnect(config)
980 anvil.configuration = openid
981 anvil.jwks = jwks
982 anvil.jwks.sig = jwks.keys[0]
983 tokens = {
984 access_token: 'valid.access.token'
985 }
986 nock(anvil.issuer).post('/token', {
987 grant_type: 'client_credentials',
988 scope: 'realm'
989 }).basicAuth({
990 user: config.client_id,
991 pass: config.client_secret
992 }).reply(200, tokens)
993 sinon.stub(AccessToken, 'verify').callsArgWith(2, null, {
994 aud: config.client_id
995 })
996 sinon.stub(IDToken, 'verify')
997 success = sinon.spy(function () {
998 return done()
999 })
1000 failure = sinon.spy(function () {
1001 return done()
1002 })
1003 promise = anvil.token({
1004 grant_type: 'client_credentials',
1005 scope: 'realm'
1006 }).then(success)['catch'](failure)
1007 return promise
1008 })
1009 afterEach(function () {
1010 AccessToken.verify.restore()
1011 IDToken.verify.restore()
1012 return nock.cleanAll()
1013 })
1014 it('should return a promise', function () {
1015 return promise.should.be['instanceof'](Promise)
1016 })
1017 it('should NOT receive an id token', function () {
1018 return IDToken.verify.should.not.have.been.called
1019 })
1020 it('should verify the access token', function () {
1021 return AccessToken.verify.should.have.been.calledWith(tokens.access_token)
1022 })
1023 it('should provide the tokens', function () {
1024 return success.should.have.been.calledWith(sinon.match(tokens))
1025 })
1026 it('should NOT provide the id claims', function () {
1027 return success.should.not.have.been.calledWith(sinon.match({
1028 id_claims: {
1029 iss: config.issuer
1030 }
1031 }))
1032 })
1033 it('should provide the access claims', function () {
1034 return success.should.have.been.calledWith(sinon.match({
1035 access_claims: {
1036 aud: config.client_id
1037 }
1038 }))
1039 })
1040 return it('should not catch an error', function () {
1041 return failure.should.not.have.been.called
1042 })
1043 })
1044 })
1045 describe('userInfo', function () {
1046 describe('with a missing access token', function () {
1047 beforeEach(function (done) {
1048 anvil = new AnvilConnect(config)
1049 anvil.configuration = openid
1050 success = sinon.spy(function () {
1051 return done()
1052 })
1053 failure = sinon.spy(function () {
1054 return done()
1055 })
1056 promise = anvil.userInfo().then(success, failure)
1057 return promise
1058 })
1059 it('should return a promise', function () {
1060 return promise.should.be['instanceof'](Promise)
1061 })
1062 it('should not provide userInfo', function () {
1063 return success.should.not.have.been.called
1064 })
1065 return it('should catch an error', function () {
1066 return failure.should.have.been.calledWith(sinon.match.instanceOf(Error))
1067 })
1068 })
1069 describe('with a successful response', function () {
1070 beforeEach(function (done) {
1071 anvil = new AnvilConnect(config)
1072 anvil.configuration = openid
1073 nock(anvil.issuer).get('/userinfo').reply(200, userinfo)
1074 success = sinon.spy(function () {
1075 return done()
1076 })
1077 failure = sinon.spy(function () {
1078 return done()
1079 })
1080 promise = anvil.userInfo({
1081 token: 'token'
1082 }).then(success)['catch'](failure)
1083 return promise
1084 })
1085 afterEach(function () {
1086 return nock.cleanAll()
1087 })
1088 it('should return a promise', function () {
1089 return promise.should.be['instanceof'](Promise)
1090 })
1091 it('should provide the userinfo', function () {
1092 return success.should.have.been.calledWith(sinon.match(userinfo))
1093 })
1094 return it('should not catch an error', function () {
1095 return failure.should.not.have.been.called
1096 })
1097 })
1098 return describe('with a failure response', function () {
1099 beforeEach(function (done) {
1100 anvil = new AnvilConnect(config)
1101 anvil.configuration = openid
1102 nock(anvil.issuer).get('/userinfo').reply(404, 'Not found')
1103 success = sinon.spy(function () {
1104 return done()
1105 })
1106 failure = sinon.spy(function () {
1107 return done()
1108 })
1109 promise = anvil.userInfo({
1110 token: 'token'
1111 }).then(success)['catch'](failure)
1112 return promise
1113 })
1114 after(function () {
1115 return nock.cleanAll()
1116 })
1117 it('should return a promise', function () {
1118 return promise.should.be['instanceof'](Promise)
1119 })
1120 it('should not provide the userinfo', function () {
1121 return success.should.not.have.been.called
1122 })
1123 return it('should catch an error', function () {
1124 return failure.should.have.been.calledWith(sinon.match.instanceOf(Error))
1125 })
1126 })
1127 })
1128 return describe('verify', function () {
1129 var ref1 = {}
1130 var claims = ref1.claims
1131 var options = ref1.options
1132 describe('with defaults and invalid token', function () {
1133 before(function (done) {
1134 anvil = new AnvilConnect(config)
1135 anvil.configuration = openid
1136 anvil.jwks = jwks
1137 anvil.jwks.sig = jwks.keys[0]
1138 sinon.stub(AccessToken, 'verify').callsArgWith(2, new Error())
1139 success = sinon.spy(function () {
1140 return done()
1141 })
1142 failure = sinon.spy(function () {
1143 return done()
1144 })
1145 promise = anvil.verify('invalid.access.token')
1146 .then(success)['catch'](failure)
1147 return promise
1148 })
1149 after(function () {
1150 return AccessToken.verify.restore()
1151 })
1152 it('should return a promise', function () {
1153 return promise.should.be['instanceof'](Promise)
1154 })
1155 it('should not provide the claims', function () {
1156 return success.should.have.not.been.called
1157 })
1158 return it('should catch an error', function () {
1159 return failure.should.have.been.called
1160 })
1161 })
1162 describe('with defaults and valid token', function () {
1163 before(function (done) {
1164 anvil = new AnvilConnect(config)
1165 anvil.configuration = openid
1166 anvil.jwks = jwks
1167 anvil.jwks.sig = jwks.keys[0]
1168 claims = {
1169 sub: 'uuid'
1170 }
1171 sinon.stub(AccessToken, 'verify').callsArgWith(2, null, claims)
1172 success = sinon.spy(function () {
1173 return done()
1174 })
1175 failure = sinon.spy(function () {
1176 return done()
1177 })
1178 promise = anvil.verify('valid.access.token')
1179 .then(success)['catch'](failure)
1180 return promise
1181 })
1182 after(function () {
1183 return AccessToken.verify.restore()
1184 })
1185 it('should return a promise', function () {
1186 return promise.should.be['instanceof'](Promise)
1187 })
1188 it('should provide the claims', function () {
1189 return success.should.have.been.calledWith(sinon.match(claims))
1190 })
1191 return it('should not catch an error', function () {
1192 return failure.should.not.have.been.called
1193 })
1194 })
1195 describe('with options and invalid token', function () {
1196 before(function (done) {
1197 anvil = new AnvilConnect(config)
1198 anvil.configuration = openid
1199 anvil.jwks = jwks
1200 anvil.jwks.sig = jwks.keys[0]
1201 sinon.stub(AccessToken, 'verify').callsArgWith(2, new Error())
1202 options = {
1203 scope: 'realm'
1204 }
1205 success = sinon.spy(function () {
1206 return done()
1207 })
1208 failure = sinon.spy(function () {
1209 return done()
1210 })
1211 promise = anvil.verify('invalid.access.token', options)
1212 .then(success)['catch'](failure)
1213 return promise
1214 })
1215 after(function () {
1216 return AccessToken.verify.restore()
1217 })
1218 it('should return a promise', function () {
1219 return promise.should.be['instanceof'](Promise)
1220 })
1221 it('should pass the options to verify', function () {
1222 return AccessToken.verify.should.have.been.calledWith(sinon.match.string, sinon.match(options))
1223 })
1224 it('should not provide the claims', function () {
1225 return success.should.have.not.been.called
1226 })
1227 return it('should catch an error', function () {
1228 return failure.should.have.been.called
1229 })
1230 })
1231 return describe('with options and valid token', function () {
1232 before(function (done) {
1233 anvil = new AnvilConnect(config)
1234 anvil.configuration = openid
1235 anvil.jwks = jwks
1236 anvil.jwks.sig = jwks.keys[0]
1237 claims = {
1238 sub: 'uuid'
1239 }
1240 sinon.stub(AccessToken, 'verify').callsArgWith(2, null, claims)
1241 options = {
1242 scope: 'realm'
1243 }
1244 success = sinon.spy(function () {
1245 return done()
1246 })
1247 failure = sinon.spy(function () {
1248 return done()
1249 })
1250 promise = anvil.verify('valid.access.token', options)
1251 .then(success)['catch'](failure)
1252 return promise
1253 })
1254 after(function () {
1255 return AccessToken.verify.restore()
1256 })
1257 it('should return a promise', function () {
1258 return promise.should.be['instanceof'](Promise)
1259 })
1260 it('should pass the options to verify', function () {
1261 return AccessToken.verify.should.have.been.calledWith(sinon.match.string, sinon.match(options))
1262 })
1263 it('should provide the claims', function () {
1264 return success.should.have.been.calledWith(sinon.match(claims))
1265 })
1266 return it('should not catch an error', function () {
1267 return failure.should.not.have.been.called
1268 })
1269 })
1270 })
1271 })
1272}).call(this)