Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix test cases using nockjs #8

Merged
merged 2 commits into from
Nov 13, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "aws-cognito-express",
"version": "1.5.0",
"version": "1.6.0",
"description": "Verification of Access and ID tokens issued by AWS Cognito for Node.js",
"main": "index.js",
"files": [
Expand Down
68 changes: 40 additions & 28 deletions test/lib/jwt-validator.spec.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
'use strict'

const { URL } = require('url')
const { expect, chance, nock, httpStatus, mockDate } = require('../index')
const { generateConfig, signToken, jwks, pems } = require('../util')
const { JWTValidator } = require('../../index')
Expand Down Expand Up @@ -189,15 +190,17 @@ describe('Validator', () => {
config = generateConfig({ withPems: true })
const validator = new JWTValidator(config)
expect(validator.pems).to.deep.equal(config.pems)
const scope = nock(validator.jwksUrl).get('').reply(httpStatus.OK, { keys: jwks })
const jwksUrl = new URL(validator.jwksUrl)
const scope = nock(jwksUrl.origin).get(jwksUrl.pathname).reply(httpStatus.OK, { keys: jwks })
await expect(validator.init()).to.eventually.be.undefined
expect(scope.isDone()).to.be.false
})

it('Should reject with InitializationError if request to the JWKs endpoint returns a non 2xx code', async () => {
const validator = new JWTValidator(config)
expect(validator.pems).to.be.null
const scope = nock(validator.jwksUrl).get('').reply(httpStatus.NOT_FOUND)
const jwksUrl = new URL(validator.jwksUrl)
const scope = nock(jwksUrl.origin).get(jwksUrl.pathname).reply(httpStatus.NOT_FOUND)
await expect(validator.init()).to.eventually.be.rejectedWith(
InitializationError,
`Initialization failed: ${httpStatus[httpStatus.NOT_FOUND]}`
Expand All @@ -209,7 +212,8 @@ describe('Validator', () => {
it('Should reject with InitializationError if some JWK is invalid', async () => {
const validator = new JWTValidator(config)
expect(validator.pems).to.be.null
const scope = nock(validator.jwksUrl).get('').reply(httpStatus.OK, {
const jwksUrl = new URL(validator.jwksUrl)
const scope = nock(jwksUrl.origin).get(jwksUrl.pathname).reply(httpStatus.OK, {
keys: jwks.concat([{ value: chance.natural() }])
})
await expect(validator.init()).to.eventually.be.rejectedWith(
Expand All @@ -223,7 +227,8 @@ describe('Validator', () => {
it('Should set the instance pems correctly', async () => {
const validator = new JWTValidator(config)
expect(validator.pems).to.be.null
const scope = nock(validator.jwksUrl).get('').reply(httpStatus.OK, { keys: jwks })
const jwksUrl = new URL(validator.jwksUrl)
const scope = nock(jwksUrl.origin).get(jwksUrl.pathname).reply(httpStatus.OK, { keys: jwks })
await expect(validator.init()).to.eventually.be.undefined
expect(scope.isDone()).to.be.true
expect(validator.pems).to.deep.equal(pems)
Expand All @@ -234,7 +239,8 @@ describe('Validator', () => {
expect(validator.pems).to.be.null

// First call.
const firstScope = nock(validator.jwksUrl).get('').reply(httpStatus.NOT_FOUND)
const jwksUrl = new URL(validator.jwksUrl)
const firstScope = nock(jwksUrl.origin).get(jwksUrl.pathname).reply(httpStatus.NOT_FOUND)
await expect(validator.init()).to.eventually.be.rejectedWith(
InitializationError,
`Initialization failed: ${httpStatus[httpStatus.NOT_FOUND]}`
Expand All @@ -244,7 +250,7 @@ describe('Validator', () => {
nock.cleanAll()

// Second call.
const secondScope = nock(validator.jwksUrl).get('').reply(httpStatus.FORBIDDEN)
const secondScope = nock(jwksUrl.origin).get(jwksUrl.pathname).reply(httpStatus.FORBIDDEN)
await expect(validator.init()).to.eventually.be.rejectedWith(
InitializationError,
`Initialization failed: ${httpStatus[httpStatus.NOT_FOUND]}`
Expand All @@ -258,14 +264,15 @@ describe('Validator', () => {
expect(validator.pems).to.be.null

// First call.
const firstScope = nock(validator.jwksUrl).get('').reply(httpStatus.OK, { keys: [jwk1] })
const jwksUrl = new URL(validator.jwksUrl)
const firstScope = nock(jwksUrl.origin).get(jwksUrl.pathname).reply(httpStatus.OK, { keys: [jwk1] })
await expect(validator.init()).to.eventually.be.undefined
expect(firstScope.isDone()).to.be.true
expect(validator.pems).to.deep.equal({ [jwk1.kid]: pems[jwk1.kid] })
nock.cleanAll()

// Second call.
const secondScope = nock(validator.jwksUrl).get('').reply(httpStatus.OK, { keys: [jwk2] })
const secondScope = nock(jwksUrl.origin).get(jwksUrl.pathname).reply(httpStatus.OK, { keys: [jwk2] })
await expect(validator.init()).to.eventually.be.undefined
expect(secondScope.isDone()).to.be.false
expect(validator.pems).to.deep.equal({ [jwk1.kid]: pems[jwk1.kid] })
Expand All @@ -274,6 +281,7 @@ describe('Validator', () => {

describe('Refresh Pems', () => {
let validator
let jwksUrl

before(() => {
if (!nock.isActive()) nock.activate()
Expand All @@ -286,7 +294,8 @@ describe('Validator', () => {
validator = new JWTValidator(config)
expect(validator.pems).to.be.null

const initScope = nock(validator.jwksUrl).get('').reply(httpStatus.OK, { keys: [jwk1] })
jwksUrl = new URL(validator.jwksUrl)
const initScope = nock(jwksUrl.origin).get(jwksUrl.pathname).reply(httpStatus.OK, { keys: [jwk1] })
await validator.init()
expect(initScope.isDone()).to.be.true
expect(validator.pems).to.deep.equal({ [jwk1.kid]: pems[jwk1.kid] })
Expand All @@ -300,14 +309,14 @@ describe('Validator', () => {
})

it('Should refresh the pems successfully', async () => {
const refreshScope = nock(validator.jwksUrl).get('').reply(httpStatus.OK, { keys: [jwk2] })
const refreshScope = nock(jwksUrl.origin).get(jwksUrl.pathname).reply(httpStatus.OK, { keys: [jwk2] })
await expect(validator.refreshPems()).to.eventually.be.undefined
expect(refreshScope.isDone()).to.be.true
expect(validator.pems).to.deep.equal({ [jwk2.kid]: pems[jwk2.kid] })
})

it('Should reject with RefreshError if refreshing the pems fails', async () => {
const refreshScope = nock(validator.jwksUrl).get('').reply(httpStatus.SERVICE_UNAVAILABLE)
const refreshScope = nock(jwksUrl.origin).get(jwksUrl.pathname).reply(httpStatus.SERVICE_UNAVAILABLE)
await expect(validator.refreshPems()).to.eventually.be.rejectedWith(
RefreshError,
`Refresh failed: ${httpStatus[httpStatus.SERVICE_UNAVAILABLE]}`
Expand All @@ -318,22 +327,22 @@ describe('Validator', () => {

it(`Should not refresh more than once every ${REFRESH_WAIT_MS} milliseconds`, async () => {
// First refresh.
const firstRefreshScope = nock(validator.jwksUrl).get('').reply(httpStatus.OK, { keys: [jwk2] })
const firstRefreshScope = nock(jwksUrl.origin).get(jwksUrl.pathname).reply(httpStatus.OK, { keys: [jwk2] })
await expect(validator.refreshPems()).to.eventually.be.undefined
expect(firstRefreshScope.isDone()).to.be.true
expect(validator.pems).to.deep.equal({ [jwk2.kid]: pems[jwk2.kid] })
nock.cleanAll()

// Second refresh should be throttled since it is within the REFRESH_WAIT_MS window.
const secondRefreshScope = nock(validator.jwksUrl).get('').reply(httpStatus.OK, { keys: [jwk1] })
const secondRefreshScope = nock(jwksUrl.origin).get(jwksUrl.pathname).reply(httpStatus.OK, { keys: [jwk1] })
await expect(validator.refreshPems()).to.eventually.be.undefined
expect(secondRefreshScope.isDone()).to.be.false
expect(validator.pems).to.deep.equal({ [jwk2.kid]: pems[jwk2.kid] })
nock.cleanAll()

// Third refresh should succeed since it is outside the REFRESH_WAIT_MS window.
mockDate.set(Date.now() + REFRESH_WAIT_MS + 1e3)
const thirdRefreshScope = nock(validator.jwksUrl).get('').reply(httpStatus.OK, { keys: [jwk1] })
const thirdRefreshScope = nock(jwksUrl.origin).get(jwksUrl.pathname).reply(httpStatus.OK, { keys: [jwk1] })
await expect(validator.refreshPems()).to.eventually.be.undefined
expect(thirdRefreshScope.isDone()).to.be.true
expect(validator.pems).to.deep.equal({ [jwk1.kid]: pems[jwk1.kid] })
Expand All @@ -343,6 +352,7 @@ describe('Validator', () => {

describe('Validate', () => {
let validator
let jwksUrl
let tokenPayload

before(() => {
Expand All @@ -352,6 +362,7 @@ describe('Validator', () => {
beforeEach(() => {
const config = generateConfig()
validator = new JWTValidator(config)
jwksUrl = new URL(validator.jwksUrl)
tokenPayload = {
email: chance.email(),
email_verified: chance.bool()
Expand All @@ -366,7 +377,7 @@ describe('Validator', () => {

it('Should reject with InitializationError if initialization fails', async () => {
const token = chance.hash()
const initScope = nock(validator.jwksUrl).get('').reply(httpStatus.NOT_FOUND)
const initScope = nock(jwksUrl.origin).get(jwksUrl.pathname).reply(httpStatus.NOT_FOUND)
await expect(validator.validate(token)).to.eventually.be.rejectedWith(
InitializationError,
`Initialization failed: ${httpStatus[httpStatus.NOT_FOUND]}`
Expand All @@ -376,13 +387,13 @@ describe('Validator', () => {

it('Should reject with InvalidJWTError if token is invalid', async () => {
const token = chance.hash()
const initScope = nock(validator.jwksUrl).get('').reply(httpStatus.OK, { keys: jwks })
const initScope = nock(jwksUrl.origin).get(jwksUrl.pathname).reply(httpStatus.OK, { keys: jwks })
await expect(validator.validate(token)).to.eventually.be.rejectedWith(InvalidJWTError, 'JWT is invalid')
expect(initScope.isDone()).to.be.true
})

it('Should reject with RefreshError if refreshing the pems fails', async () => {
const initScope = nock(validator.jwksUrl).get('').reply(httpStatus.OK, { keys: [jwk2] })
const initScope = nock(jwksUrl.origin).get(jwksUrl.pathname).reply(httpStatus.OK, { keys: [jwk2] })
await expect(validator.init()).to.eventually.be.undefined
expect(validator.pems).to.deep.equal({ [jwk2.kid]: pems[jwk2.kid] })
expect(initScope.isDone()).to.be.true
Expand All @@ -393,7 +404,7 @@ describe('Validator', () => {
issuer: chance.hash(),
tokenUse: TOKEN_USE.ACCESS
})
const refreshScope = nock(validator.jwksUrl).get('').reply(httpStatus.SERVICE_UNAVAILABLE)
const refreshScope = nock(jwksUrl.origin).get(jwksUrl.pathname).reply(httpStatus.SERVICE_UNAVAILABLE)
await expect(validator.validate(token)).to.eventually.be.rejectedWith(
RefreshError,
`Refresh failed: ${httpStatus[httpStatus.SERVICE_UNAVAILABLE]}`
Expand All @@ -402,7 +413,7 @@ describe('Validator', () => {
})

it('Should reject with InvalidJWTError if there is no pem to verify the token signature', async () => {
const initScope = nock(validator.jwksUrl).get('').reply(httpStatus.OK, { keys: [jwk2] })
const initScope = nock(jwksUrl.origin).get(jwksUrl.pathname).reply(httpStatus.OK, { keys: [jwk2] })
await expect(validator.init()).to.eventually.be.undefined
expect(validator.pems).to.deep.equal({ [jwk2.kid]: pems[jwk2.kid] })
expect(initScope.isDone()).to.be.true
Expand All @@ -413,7 +424,7 @@ describe('Validator', () => {
issuer: chance.hash(),
tokenUse: TOKEN_USE.ACCESS
})
const refreshScope = nock(validator.jwksUrl).get('').reply(httpStatus.OK, { keys: [jwk2] })
const refreshScope = nock(jwksUrl.origin).get(jwksUrl.pathname).reply(httpStatus.OK, { keys: [jwk2] })
await expect(validator.validate(token)).to.eventually.be.rejectedWith(
InvalidJWTError,
'No pem found to verify JWT signature'
Expand All @@ -422,7 +433,7 @@ describe('Validator', () => {
})

it('Should reject with InvalidJWTError if token signature is invalid', async () => {
const initScope = nock(validator.jwksUrl).get('').reply(httpStatus.OK, { keys: jwks })
const initScope = nock(jwksUrl.origin).get(jwksUrl.pathname).reply(httpStatus.OK, { keys: jwks })
const token = signToken('key_1', tokenPayload, {
audience: chance.pickone(validator.audience),
issuer: validator.iss,
Expand All @@ -434,7 +445,7 @@ describe('Validator', () => {
})

it('Should reject with InvalidJWTError if token audience is invalid', async () => {
const initScope = nock(validator.jwksUrl).get('').reply(httpStatus.OK, { keys: jwks })
const initScope = nock(jwksUrl.origin).get(jwksUrl.pathname).reply(httpStatus.OK, { keys: jwks })
const token = signToken('key_1', tokenPayload, {
audience: chance.hash(),
issuer: validator.iss,
Expand All @@ -445,7 +456,7 @@ describe('Validator', () => {
})

it('Should reject with InvalidJWTError if token issuer is invalid', async () => {
const initScope = nock(validator.jwksUrl).get('').reply(httpStatus.OK, { keys: jwks })
const initScope = nock(jwksUrl.origin).get(jwksUrl.pathname).reply(httpStatus.OK, { keys: jwks })
const token = signToken('key_1', tokenPayload, {
audience: chance.pickone(validator.audience),
issuer: chance.url(),
Expand All @@ -459,7 +470,8 @@ describe('Validator', () => {
const config = generateConfig()
config.tokenUse = [TOKEN_USE.ACCESS]
validator = new JWTValidator(config)
const initScope = nock(validator.jwksUrl).get('').reply(httpStatus.OK, { keys: jwks })
jwksUrl = new URL(validator.jwksUrl)
const initScope = nock(jwksUrl.origin).get(jwksUrl.pathname).reply(httpStatus.OK, { keys: jwks })
const token = signToken('key_1', tokenPayload, {
audience: chance.pickone(validator.audience),
issuer: validator.iss,
Expand All @@ -473,7 +485,7 @@ describe('Validator', () => {
})

it('Should reject with InvalidJWTError if token is expired', async () => {
const initScope = nock(validator.jwksUrl).get('').reply(httpStatus.OK, { keys: jwks })
const initScope = nock(jwksUrl.origin).get(jwksUrl.pathname).reply(httpStatus.OK, { keys: jwks })
const token = signToken('key_1', tokenPayload, {
audience: chance.pickone(validator.audience),
issuer: validator.iss,
Expand All @@ -488,7 +500,7 @@ describe('Validator', () => {
})

it('Should resolve with the token payload', async () => {
const initScope = nock(validator.jwksUrl).get('').reply(httpStatus.OK, { keys: jwks })
const initScope = nock(jwksUrl.origin).get(jwksUrl.pathname).reply(httpStatus.OK, { keys: jwks })
const token = signToken('key_1', tokenPayload, {
audience: chance.pickone(validator.audience),
issuer: validator.iss,
Expand All @@ -504,7 +516,7 @@ describe('Validator', () => {
})

it('Should resolve with the token payload after refreshing the pems', async () => {
const initScope = nock(validator.jwksUrl).get('').reply(httpStatus.OK, { keys: [jwk2] })
const initScope = nock(jwksUrl.origin).get(jwksUrl.pathname).reply(httpStatus.OK, { keys: [jwk2] })
await expect(validator.init()).to.eventually.be.undefined
expect(validator.pems).to.deep.equal({ [jwk2.kid]: pems[jwk2.kid] })
expect(initScope.isDone()).to.be.true
Expand All @@ -515,7 +527,7 @@ describe('Validator', () => {
issuer: validator.iss,
tokenUse: chance.pickone(validator.tokenUse)
})
const refreshScope = nock(validator.jwksUrl).get('').reply(httpStatus.OK, { keys: [jwk1] })
const refreshScope = nock(jwksUrl.origin).get(jwksUrl.pathname).reply(httpStatus.OK, { keys: [jwk1] })
const payload = await validator.validate(token)
expect(payload).to.be.an('object').that.has.all.keys(
'aud', 'email', 'email_verified', 'exp', 'iat', 'iss', 'token_use'
Expand Down
4 changes: 2 additions & 2 deletions test/middlewares/authenticate.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ describe('Authenticate', () => {
tokenPayload = { email: chance.email(), email_verified: chance.bool() }
issuer = `https://cognito-idp.${config.region}.amazonaws.com/${config.userPoolId}`
nock.cleanAll()
initScope = nock(`${issuer}/.well-known/jwks.json`).get('').reply(httpStatus.OK, { keys: jwks })
initScope = nock(issuer).get('/.well-known/jwks.json').reply(httpStatus.OK, { keys: jwks })
})

after(() => {
Expand Down Expand Up @@ -124,7 +124,7 @@ describe('Authenticate', () => {
// Clean mocks.
next.resetHistory()
nock.cleanAll()
initScope = nock(`${issuer}/.well-known/jwks.json`).get('').reply(httpStatus.OK, { keys: jwks })
initScope = nock(issuer).get('/.well-known/jwks.json').reply(httpStatus.OK, { keys: jwks })

// Second request already has the validator initialized.
const secondRequestTokenPayload = { email: chance.email(), email_verified: chance.bool() }
Expand Down