From df1ac940cab1cd086a8dba811ac1bc90bf9e5be3 Mon Sep 17 00:00:00 2001 From: Andrea Carraro Date: Fri, 21 Apr 2023 14:55:58 +0200 Subject: [PATCH] test: run against mocked server (needs refactor propsed by @gnarea) --- package.json | 3 +- ...tion.test.js => auth0.integration.test.js} | 6 +- test/oauth2-mocked-server.integration.test.js | 108 ++++++++++++++++++ 3 files changed, 113 insertions(+), 4 deletions(-) rename test/{integration.test.js => auth0.integration.test.js} (95%) create mode 100644 test/oauth2-mocked-server.integration.test.js diff --git a/package.json b/package.json index f0f10fd..ac216f6 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "scripts": { "test": "jest ./test/test.js --coverage", "test:ci": "npm run lint && npm run test -- --ci --coverageReporters=json && npm run test:types", - "test:integration": "jest ./test/integration.test.js", + "test:integration": "jest ./test/*.integration.test.js", "test:types": "tsd", "lint": "eslint index.js test", "prepublishOnly": "npm run test:ci", @@ -68,6 +68,7 @@ "fastify": "^4.0.2", "jest": "^29.0.0", "nock": "^13.0.2", + "oauth2-mock-server": "^5.0.2", "prettier": "^2.0.5", "tsd": "^0.28.0", "typescript": "^5.0.2" diff --git a/test/integration.test.js b/test/auth0.integration.test.js similarity index 95% rename from test/integration.test.js rename to test/auth0.integration.test.js index 57af9b6..4784f43 100644 --- a/test/integration.test.js +++ b/test/auth0.integration.test.js @@ -13,11 +13,11 @@ if ( async function buildServer() { const server = Fastify() - // Setup fastify-auth0-verify await server.register(require('../'), { - domain: process.env.AUTH0_DOMAIN, - secret: process.env.AUTH0_CLIENT_SECRET + domain: process.env.AUTH0_DOMAIN + '/.well-known/jwks.json', + secret: process.env.AUTH0_CLIENT_SECRET, + issuer: new URL('https://' + process.env.AUTH0_DOMAIN).toString() }) // Setup auth0 protected route diff --git a/test/oauth2-mocked-server.integration.test.js b/test/oauth2-mocked-server.integration.test.js new file mode 100644 index 0000000..671fd21 --- /dev/null +++ b/test/oauth2-mocked-server.integration.test.js @@ -0,0 +1,108 @@ +const Fastify = require('fastify') +const { OAuth2Server } = require('oauth2-mock-server') + +async function buildOAuthServer() { + const server = new OAuth2Server() + + // Generate a new RSA key and add it to the keystore + await server.issuer.keys.generate('RS256') + + // Start the server + await server.start(8080, 'localhost') + return server +} + +async function buildServer({ oAuthServerUrl }) { + const server = Fastify() + + // Setup fastify-auth0-verify + await server.register(require('../'), { + domain: `${oAuthServerUrl}/jwks`, + audience: 'fastify-auth0-verify-test-api', + issuer: oAuthServerUrl + }) + + // Setup auth0 protected route + server.get('/protected', { preValidation: server.authenticate }, (req, reply) => { + reply.send({ route: 'Protected route' }) + }) + + // Setup auth0 public route + server.get('/public', (req, reply) => { + reply.send({ route: 'Public route' }) + }) + + await server.listen({ port: 0 }) + return server +} + +describe('Authentication against Auth0', () => { + let server + let OAuthServer + + beforeAll(async function () { + OAuthServer = await buildOAuthServer() + server = await buildServer({ oAuthServerUrl: OAuthServer.issuer.url }) + }) + + afterAll(async () => { + server.close() + await OAuthServer.stop() + }) + + it('Protects protected routes', async () => { + const publicResponse = await server.inject('/public') + expect(publicResponse.statusCode).toEqual(200) + expect(publicResponse.json()).toEqual({ route: 'Public route' }) + + const protectedResponseWithoutAuthHeader = await server.inject('/protected') + expect(protectedResponseWithoutAuthHeader.statusCode).toEqual(401) + expect(protectedResponseWithoutAuthHeader.json()).toEqual({ + error: 'Unauthorized', + message: 'Missing Authorization HTTP header.', + statusCode: 401 + }) + + const invalidAuthToken = + 'Bearer eyuhbGcpOpuSUzI1NpIsInR5cCI6IkpOVCIsImtpZCI6IkNPTFuKTFumQ2tZeURuSE1aamNUap7.eyupc3MpOpuodHRwczovL2Rldp0zZTh1d2poYjF4MnZqY2U4LnVzLmF1dGgwLmNvbS8pLCuzdWIpOpu6RUIzaEM0VUhrV3hjQ3uOQ2d2RzZlNkdmQOuZRkRrYUBjbGllbnRzIpwpYOVkIjopSldULOZlcmlmeS10ZON0IpwpaWF0IjoxNjgxODM0NjYxLCuleHApOjE2ODE5MjEwNjEsImF6cCI6InpFQjNoQzRVSGtOeGNDcldDZ3ZHNmU2R2ZBcllGRGthIpwpZ3R5IjopY2xpZW50LWNyZWRlbnRpYWxzIn0.MdxfrZF5EB9ByFABzEdBGENjc0d9eoML_TDKftxrg2352VqvoD3dnxxn1rpIAqjcpWSI4BKvf3hNlcDwoOyhT2kmHxDgcNv22dG9ZAY5vEkm6csDtUeBbVuqdjx30zwbcYDf_pZ4euuCLE-ysOI8WpvYvsOGTjGBpjdFZAyGqPIL0RTUrtwh6lrVzGGl9oKPQgq-ZuFOtUQOO7w4jItHZ40SpvzPYfrLY4P6DfYbxcwSTc9OjE86vvUON0EunTdjhkyml-c28svnxu5WFvfsuUT56Cbw1AYKogg12-OHLYuyS2VQblxCQfIogaDZPTY114M8PCb0ZBL19jNO6oxzA' + const protectedResponseWithInvalidAuthHeader = await server.inject({ + method: 'GET', + url: '/protected', + headers: { + Authorization: invalidAuthToken + } + }) + expect(protectedResponseWithInvalidAuthHeader.statusCode).toEqual(401) + expect(protectedResponseWithInvalidAuthHeader.json()).toEqual({ + code: 'FST_JWT_AUTHORIZATION_TOKEN_INVALID', + error: 'Unauthorized', + message: 'Authorization token is invalid: The token header is not a valid base64url serialized JSON.', + statusCode: 401 + }) + }) + + it('Returns protected route when expected auth header is provided', async () => { + const authResponse = await fetch(`${OAuthServer.issuer.url}/token`, { + method: 'POST', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify({ + client_id: 'client_id', + client_secret: 'client_secret', + audience: 'audience', + grant_type: 'client_credentials' + }) + }) + + const { token_type: tokenType, access_token: accessToken } = await authResponse.json() + const protectedResponse = await server.inject({ + method: 'GET', + url: '/protected', + headers: { + Authorization: `${tokenType} ${accessToken}` + } + }) + + expect(protectedResponse.statusCode).toEqual(200) + expect(protectedResponse.json()).toEqual({ route: 'Protected route' }) + }) +})