From 16eb49000b0d32b9cfa120de74a92937861eb80b Mon Sep 17 00:00:00 2001 From: Antoine Arlaud Date: Wed, 21 Jun 2023 17:17:15 +0200 Subject: [PATCH] feat: add broker type validtion middlwr --- config.default.json | 3 + lib/config.js | 1 - lib/server/broker-middleware.ts | 23 ++++++ lib/server/index.js | 3 +- package.json | 2 +- .../server-client-universal.test.ts | 80 +++++++++++++++++++ 6 files changed, 109 insertions(+), 3 deletions(-) create mode 100644 config.default.json create mode 100644 lib/server/broker-middleware.ts create mode 100644 test/functional/server-client-universal.test.ts diff --git a/config.default.json b/config.default.json new file mode 100644 index 000000000..1cc6bf75d --- /dev/null +++ b/config.default.json @@ -0,0 +1,3 @@ +{ + "BROKER_SERVER_UNIVERSAL_CONFIG_ENABLED": false +} \ No newline at end of file diff --git a/lib/config.js b/lib/config.js index 31e27894e..ab27b9876 100644 --- a/lib/config.js +++ b/lib/config.js @@ -90,7 +90,6 @@ dotenv.config({ expand(process.env); const res = Object.assign({}, camelify(config), camelify(process.env)); - if (res.caCert) { res.caCert = fs.readFileSync(path.resolve(process.cwd(), res.caCert)); } diff --git a/lib/server/broker-middleware.ts b/lib/server/broker-middleware.ts new file mode 100644 index 000000000..b44127fb3 --- /dev/null +++ b/lib/server/broker-middleware.ts @@ -0,0 +1,23 @@ +import { Request, Response, NextFunction } from 'express'; +import * as logger from '../log'; +import * as config from '../config'; +export const validateBrokerTypeMiddleware = ( + req: Request, + res: Response, + next: NextFunction, +) => { + const localConfig = config as unknown as Record; + if ( + localConfig.brokerServerUniversalConfigEnabled && + !req?.headers['x-snyk-broker-type'] + ) { + const logContext = { url: req.url, headers: req.headers }; + logger.warn( + { logContext }, + 'Error: Request does not contain the x-snyk-broker-type header', + ); + // Will eventually return an error when all services will have this enabled + // return res.status(400).json({ error: 'Missing x-broker-type header' }); + } + next(); // Passes the request to the next middleware +}; diff --git a/lib/server/index.js b/lib/server/index.js index 732dbb2cf..a64682558 100644 --- a/lib/server/index.js +++ b/lib/server/index.js @@ -5,6 +5,7 @@ const version = require('../version'); const { maskToken, hashToken } = require('../token'); const metrics = require('../metrics'); const { applyPrometheusMiddleware } = require('./prometheus-middleware'); +const { validateBrokerTypeMiddleware } = require('./broker-middleware'); module.exports = async ({ config = {}, port = null, filters = {} }) => { logger.info({ version }, 'running in server mode'); @@ -33,7 +34,6 @@ module.exports = async ({ config = {}, port = null, filters = {} }) => { if (!process.env.JEST_WORKER_ID) { app.use(applyPrometheusMiddleware()); } - app.get('/connection-status/:token', (req, res) => { const token = req.params.token; const maskedToken = maskToken(token); @@ -82,6 +82,7 @@ module.exports = async ({ config = {}, port = null, filters = {} }) => { next(); }, + validateBrokerTypeMiddleware, relay.request(filters.public), ); diff --git a/package.json b/package.json index 2fb051567..2327fe32d 100644 --- a/package.json +++ b/package.json @@ -83,7 +83,7 @@ "qs": "^6.9.1", "request": "^2.88.1", "request-promise-native": "^1.0.9", - "snyk-config": "^4.0.0-rc.2", + "snyk-config": "^4.0.0", "then-fs": "^2.0.0", "tunnel": "0.0.6", "undefsafe": "^2.0.2", diff --git a/test/functional/server-client-universal.test.ts b/test/functional/server-client-universal.test.ts new file mode 100644 index 000000000..51ddeedac --- /dev/null +++ b/test/functional/server-client-universal.test.ts @@ -0,0 +1,80 @@ +process.env.SNYK_BROKER_SERVER_UNIVERSAL_CONFIG_ENABLED = 'true'; +import * as path from 'path'; +import { axiosClient } from '../setup/axios-client'; +import { + BrokerClient, + closeBrokerClient, + createBrokerClient, +} from '../setup/broker-client'; +import { + BrokerServer, + closeBrokerServer, + createBrokerServer, + waitForBrokerClientConnection, +} from '../setup/broker-server'; +import { TestWebServer, createTestWebServer } from '../setup/test-web-server'; + +const fixtures = path.resolve(__dirname, '..', 'fixtures'); +const serverAccept = path.join(fixtures, 'server', 'filters.json'); +const clientAccept = path.join(fixtures, 'client', 'filters.json'); + +describe('proxy requests originating from behind the broker server', () => { + let tws: TestWebServer; + let bs: BrokerServer; + let bc: BrokerClient; + let brokerToken: string; + + const spyLogWarn = jest + .spyOn(require('bunyan').prototype, 'warn') + .mockImplementation((value) => { + return value; + }); + + beforeAll(async () => { + tws = await createTestWebServer(); + + bs = await createBrokerServer({ filters: serverAccept, port: 8100 }); + + bc = await createBrokerClient({ + brokerServerUrl: `http://localhost:${bs.port}`, + brokerToken: 'broker-token-12345', + filters: clientAccept, + type: 'client', + }); + ({ brokerToken } = await waitForBrokerClientConnection(bs)); + }); + + afterEach(async () => { + spyLogWarn.mockReset(); + }); + afterAll(async () => { + spyLogWarn.mockReset(); + await tws.server.close(); + await closeBrokerClient(bc); + await closeBrokerServer(bs); + }); + + it('successfully broker GET', async () => { + const response = await axiosClient.get( + `http://localhost:${bs.port}/broker/${brokerToken}/echo-param/xyz`, + ); + + expect(response.status).toEqual(200); + expect(response.data).toEqual('xyz'); + }); + + it('successfully warn logs requests without x-snyk-broker-type header', async () => { + const response = await axiosClient.get( + `http://localhost:${bs.port}/broker/${brokerToken}/echo-param/xyz`, + ); + + expect(response.status).toEqual(200); + expect(response.data).toEqual('xyz'); + + expect(spyLogWarn).toHaveBeenCalledTimes(1); + expect(spyLogWarn).toHaveBeenCalledWith( + expect.any(Object), + 'Error: Request does not contain the x-snyk-broker-type header', + ); + }); +});