diff --git a/deploy/app.js b/deploy/app.js index 95f99a8783897b2a43a93865ea35540cfa9aa350..14922bfda618de09ca3e09390f800f3a83da007e 100644 --- a/deploy/app.js +++ b/deploy/app.js @@ -42,9 +42,18 @@ app.use((req, _, next) => { const { configureAuth, ready: authReady } = require('./auth') -const store = new MemoryStore({ - checkPeriod: 86400000 -}) +/** + * memorystore (or perhaps lru-cache itself) does not properly close when server shuts + * this causes problems during tests + * So when testing app.js, set USE_DEFAULT_MEMORY_STORE to true + * see app.spec.js + */ +const { USE_DEFAULT_MEMORY_STORE } = process.env +const store = USE_DEFAULT_MEMORY_STORE + ? (console.warn(`USE_DEFAULT_MEMORY_STORE is set to true, memleak expected. Do NOT use in prod.`), null) + : new MemoryStore({ + checkPeriod: 86400000 + }) const SESSIONSECRET = process.env.SESSIONSECRET || 'this is not really a random session secret' @@ -67,14 +76,15 @@ if (process.env.DISABLE_CSP && process.env.DISABLE_CSP === 'true') { require('./csp')(app) } - /** * configure Auth * async function, but can start server without */ -configureAuth(app) - .then(() => console.log('configure auth properly')) - .catch(e => console.error('configure auth failed', e)) + +(async () => { + await configureAuth(app) + app.use('/user', require('./user')) +})() const PUBLIC_PATH = process.env.NODE_ENV === 'production' ? path.join(__dirname, 'public') @@ -128,10 +138,7 @@ app.use(require('./devBanner')) /** * populate nonce token */ -const indexTemplate = require('fs').readFileSync( - path.join(PUBLIC_PATH, 'index.html'), - 'utf-8' -) +const { indexTemplate } = require('./constants') app.get('/', cookieParser(), (req, res) => { const iavError = req.cookies && req.cookies['iav-error'] @@ -154,11 +161,6 @@ app.get('/', cookieParser(), (req, res) => { app.use('/logo', require('./logo')) -/** - * User route, for user profile/management - */ -app.use('/user', require('./user')) - app.get('/ready', async (req, res) => { const authIsReady = await authReady() const allReady = [ diff --git a/deploy/app.spec.js b/deploy/app.spec.js new file mode 100644 index 0000000000000000000000000000000000000000..0b38b80531a078a300d40e5598637cd830b5c58c --- /dev/null +++ b/deploy/app.spec.js @@ -0,0 +1,72 @@ +const { expect } = require('chai') +const fs = require('fs') +const { assert } = require('console') +const express = require('express') +const got = require('got') +const sinon = require('sinon') + +let server +const PORT=12345 + +describe('authentication', () => { + + /** + * memorystore (or perhaps lru-cache itself) does not properly close when server.close() + * use default memory store for tests + */ + process.env['USE_DEFAULT_MEMORY_STORE'] = true + + const fakeFunctionObj = { + fakeAuthConfigureAuth: (req, res, next) => next(), + fakeAuthReady: async () => true, + fakeUserRouterFn: (req, res, next) => res.status(200).send() + } + + before(async () => { + const auth = require('./auth') + const authConfigureAuthStub = sinon.stub(auth, 'configureAuth') + const authIsReadyStub = sinon.stub(auth, 'ready') + + require.cache[require.resolve('./datasets')] = { + exports: (req, res, next) => next() + } + + require.cache[require.resolve('./saneUrl')] = { + exports: (req, res, next) => next() + } + + require.cache[require.resolve('./user')] = { + exports: fakeFunctionObj.fakeUserRouterFn + } + + require.cache[require.resolve('./constants')] = { + exports: { + indexTemplate: `` + } + } + + authConfigureAuthStub.callsFake(app => { + app.use(fakeFunctionObj.fakeAuthConfigureAuth) + return Promise.resolve() + }) + + const expressApp = express() + const app = require('./app') + expressApp.use(app) + server = expressApp.listen(PORT) + }) + + after(() => { + server.close() + }) + + it('fakeAuthConfigureAuth is called before user router', async () => { + const spyFakeAuthConfigureAuth = sinon.spy(fakeFunctionObj, 'fakeAuthConfigureAuth') + const spyFakeUserRouterFn = sinon.spy(fakeFunctionObj, 'fakeUserRouterFn') + await got(`http://localhost:${PORT}/user`) + assert( + spyFakeAuthConfigureAuth.calledBefore(spyFakeUserRouterFn), + 'fakeAuthConfigureAuth is called before user router' + ) + }) +}) diff --git a/deploy/auth/index.js b/deploy/auth/index.js index d0f288d894b2c534e02811d9d6f2225f9d3631a8..d3ce8cef15b8c2ea6f667babbcd9030694f3f605 100644 --- a/deploy/auth/index.js +++ b/deploy/auth/index.js @@ -1,4 +1,3 @@ -const objStoreDb = new Map() const HOST_PATHNAME = process.env.HOST_PATHNAME || '' const { retry } = require('../../common/util') @@ -14,7 +13,7 @@ const configureAuth = async (app) => { const hbpOidc2 = require('./hbp-oidc-v2') const obj = await require('./util')() - const { initPassportJs } = obj + const { initPassportJs, objStoreDb } = obj initPassportJs(app) await retry(() => hbpOidc(app), { timeout: 1000, retries: 3 }) diff --git a/deploy/auth/util.js b/deploy/auth/util.js index 34ad7955fb3e054cc045a74fdd9c8b87f485dd62..9b5bbaadbfad423b530af5ebf360d369845371cb 100644 --- a/deploy/auth/util.js +++ b/deploy/auth/util.js @@ -1,4 +1,5 @@ const { configureAuth, jwtDecode } = require('./oidc') +const objStoreDb = new Map() const HOSTNAME = process.env.HOSTNAME || 'http://localhost:3000' const HOST_PATHNAME = process.env.HOST_PATHNAME || '' @@ -50,6 +51,7 @@ const getPublicAccessToken = async () => { } const initPassportJs = app => { + console.log('init passport js') const passport = require('passport') app.use(passport.initialize()) @@ -70,6 +72,13 @@ const initPassportJs = app => { module.exports = async () => { + /** + * this configuration is required to acquire valid + * access tokens using refresh token + * + * This is so that datasets can be retrieved when user + * is not authenticated + */ const { client } = await configureAuth({ clientId, clientSecret, @@ -85,6 +94,7 @@ module.exports = async () => { return { initPassportJs, + objStoreDb, getPublicAccessToken: async () => await getPublicAccessToken() } } \ No newline at end of file diff --git a/deploy/constants.js b/deploy/constants.js new file mode 100644 index 0000000000000000000000000000000000000000..32e07da87525c172091e0c1e03426a1771e44822 --- /dev/null +++ b/deploy/constants.js @@ -0,0 +1,14 @@ +const fs = require('fs') + +const PUBLIC_PATH = process.env.NODE_ENV === 'production' + ? path.join(__dirname, 'public') + : path.join(__dirname, '..', 'dist', 'aot') + +const indexTemplate = fs.readFileSync( + path.join(PUBLIC_PATH, 'index.html'), + 'utf-8' +) + +module.exports = { + indexTemplate +}