From 21e6e903b2fc835fd755b8b9eb5c8e94f43133d9 Mon Sep 17 00:00:00 2001 From: Antoine Arlaud Date: Fri, 24 Jan 2025 15:52:32 +0100 Subject: [PATCH] feat: add server side connection auth management --- accept-server.local.json | 18 ++ lib/server/auth/authHelpers.ts | 50 ++++++ lib/server/auth/connectionWatchdog.ts | 30 ++++ lib/server/index.ts | 21 ++- lib/server/routesHandlers/authHandlers.ts | 88 ++++++++++ .../routesHandlers/connectionStatusHandler.ts | 2 +- .../routesHandlers/httpRequestHandler.ts | 10 +- .../routesHandlers/postResponseHandler.ts | 31 ++++ lib/server/socket.ts | 155 ++++++++++++------ lib/server/socketHandlers/closeHandler.ts | 2 +- lib/server/socketHandlers/identifyHandler.ts | 24 ++- package.json | 6 +- ...erver-client-universal-bearer-auth.test.ts | 4 +- ...lient-universal-pooled-credentials.test.ts | 4 +- .../server-client-universal.test.ts | 3 +- 15 files changed, 382 insertions(+), 66 deletions(-) create mode 100644 accept-server.local.json create mode 100644 lib/server/auth/authHelpers.ts create mode 100644 lib/server/auth/connectionWatchdog.ts create mode 100644 lib/server/routesHandlers/authHandlers.ts diff --git a/accept-server.local.json b/accept-server.local.json new file mode 100644 index 000000000..07b8e3f24 --- /dev/null +++ b/accept-server.local.json @@ -0,0 +1,18 @@ +{ + "//": "private refers to what's internal to snyk, i.e. the snyk.io server", + "private": [ + { + "//": "send any type of request to our connected clients", + "method": "any", + "path": "/*" + } + ], + "public": [ + { + "//": "send any type of request to our connected clients", + "method": "any", + "path": "/*" + } + ] +} + diff --git a/lib/server/auth/authHelpers.ts b/lib/server/auth/authHelpers.ts new file mode 100644 index 000000000..d515e3bc8 --- /dev/null +++ b/lib/server/auth/authHelpers.ts @@ -0,0 +1,50 @@ +import { getConfig } from '../../common/config/config'; +import { PostFilterPreparedRequest } from '../../common/relay/prepareRequest'; +import { maskToken } from '../../common/utils/token'; +import { makeSingleRawRequestToDownstream } from '../../hybrid-sdk/http/request'; +import { log as logger } from '../../logs/logger'; + +export const validateBrokerClientCredentials = async ( + authHeaderValue: string, + brokerClientId: string, + brokerConnectionIdentifier: string, +) => { + const body = { + data: { + type: 'broker_connection', + attributes: { + broker_client_id: brokerClientId, + }, + }, + }; + + const req: PostFilterPreparedRequest = { + url: `${ + getConfig().apiHostname + }/hidden/brokers/connections/${brokerConnectionIdentifier}/auth/validate?version=2024-02-08~experimental`, + headers: { + authorization: authHeaderValue, + 'Content-type': 'application/vnd.api+json', + }, + method: 'POST', + body: JSON.stringify(body), + }; + logger.debug( + { maskToken: maskToken(brokerConnectionIdentifier) }, + `Validate Broker Client Credentials request`, + ); + const response = await makeSingleRawRequestToDownstream(req); + logger.debug( + { validationResponseCode: response.statusCode }, + 'Validate Broker Client Credentials response', + ); + if (response.statusCode === 201) { + return true; + } else { + logger.debug( + { statusCode: response.statusCode, message: response.statusText }, + `Broker ${brokerConnectionIdentifier} client ID ${brokerClientId} failed validation.`, + ); + return false; + } +}; diff --git a/lib/server/auth/connectionWatchdog.ts b/lib/server/auth/connectionWatchdog.ts new file mode 100644 index 000000000..c66ae7b10 --- /dev/null +++ b/lib/server/auth/connectionWatchdog.ts @@ -0,0 +1,30 @@ +import { getConfig } from '../../common/config/config'; +import { getSocketConnections } from '../socket'; +import { log as logger } from '../../logs/logger'; + +export const disconnectConnectionsWithStaleCreds = async () => { + const connections = getSocketConnections(); + const connectionsIterator = connections.entries(); + for (const [identifier, connection] of connectionsIterator) { + connection.forEach((client) => { + if (!isDateWithinAnHourAndFiveSec(client.credsValidationTime!)) { + logger.debug( + { + connection: `${identifier}`, + credsLastValidated: client.credsValidationTime, + }, + 'Cutting off connection.', + ); + client.socket!.end(); + } + }); + } +}; + +const isDateWithinAnHourAndFiveSec = (date: string): boolean => { + const dateInMs = new Date(date); // Convert ISO string to Date + const now = Date.now(); // Get current time in milliseconds + const staleConnectionsCleanupInterval = + getConfig().STALE_CONNECTIONS_CLEANUP_FREQUENCY ?? 65 * 60 * 1000; // 1h05 hour in milliseconds + return now - dateInMs.getTime() < staleConnectionsCleanupInterval; +}; diff --git a/lib/server/index.ts b/lib/server/index.ts index e6bb05b09..46aea90d0 100644 --- a/lib/server/index.ts +++ b/lib/server/index.ts @@ -13,6 +13,8 @@ import { getForwardHttpRequestHandler } from './socketHandlers/initHandlers'; import { loadAllFilters } from '../common/filter/filtersAsync'; import { FiltersType } from '../common/types/filter'; import filterRulesLoader from '../common/filter/filter-rules-loading'; +import { authRefreshHandler } from './routesHandlers/authHandlers'; +import { disconnectConnectionsWithStaleCreds } from './auth/connectionWatchdog'; export const main = async (serverOpts: ServerOpts) => { logger.info({ version }, 'Broker starting in server mode'); @@ -64,7 +66,24 @@ export const main = async (serverOpts: ServerOpts) => { getForwardHttpRequestHandler(), ); - app.post('/response-data/:brokerToken/:streamingId', handlePostResponse); + if (loadedServerOpts.config.BROKER_SERVER_MANDATORY_AUTH_ENABLED) { + app.post( + '/hidden/brokers/connections/:identifier/auth/refresh', + authRefreshHandler, + ); + app.post( + '/hidden/broker/response-data/:brokerToken/:streamingId', + handlePostResponse, + ); + + setInterval( + disconnectConnectionsWithStaleCreds, + loadedServerOpts.config.STALE_CONNECTIONS_CLEANUP_FREQUENCY ?? + 10 * 60 * 1000, + ); + } else { + app.post('/response-data/:brokerToken/:streamingId', handlePostResponse); + } app.get('/', (req, res) => res.status(200).json({ ok: true, version })); diff --git a/lib/server/routesHandlers/authHandlers.ts b/lib/server/routesHandlers/authHandlers.ts new file mode 100644 index 000000000..c6ab85ea9 --- /dev/null +++ b/lib/server/routesHandlers/authHandlers.ts @@ -0,0 +1,88 @@ +import { Request, Response } from 'express'; +import { validateBrokerClientCredentials } from '../auth/authHelpers'; +import { log as logger } from '../../logs/logger'; +import { validate } from 'uuid'; +import { getSocketConnectionByIdentifier } from '../socket'; +import { maskToken } from '../../common/utils/token'; +interface BrokerConnectionAuthRequest { + data: { + attributes: { + broker_client_id: string; + }; + id: string; + type: 'broker_connection'; + }; +} +export const authRefreshHandler = async (req: Request, res: Response) => { + const credentialsFromHeader = + req.headers['Authorization'] ?? req.headers['authorization']; + const role = req.query['connection_role']; + const credentials = `${credentialsFromHeader}`; + const brokerAppClientId = + req.headers[`${process.env.SNYK_INTERNAL_AUTH_CLIENT_ID_HEADER}`]; + const identifier = req.params.identifier; + logger.debug( + { maskedToken: maskToken(identifier), brokerAppClientId, role }, + `Auth Refresh`, + ); + const body = JSON.parse(req.body.toString()) as BrokerConnectionAuthRequest; + const brokerClientId = body.data.attributes.broker_client_id; + if (!validate(brokerClientId) || !validate(brokerAppClientId)) { + logger.warn( + { identifier, brokerClientId, brokerAppClientId }, + 'Invalid credentials', + ); + return res.status(401).send('Invalid parameters or credentials.'); + } + + const connection = getSocketConnectionByIdentifier(identifier); + const currentClient = connection + ? connection.find( + (x) => x.metadata.clientId === brokerClientId && x.role === role, + ) + : null; + logger.debug({ identifier, brokerClientId, role }, 'Validating credentials'); + if ( + credentials === undefined || + brokerAppClientId === undefined || + !connection || + !currentClient + ) { + logger.debug( + { identifier, brokerClientId, role, credentials }, + 'Invalid credentials', + ); + return res.status(401).send('Invalid credentials.'); + } else { + const credsCheckResponse = await validateBrokerClientCredentials( + credentials, + brokerClientId as string, + identifier, + ); + logger.debug( + { credsCheckResponse: credsCheckResponse }, + 'Client Creds validation response.', + ); + if (credsCheckResponse) { + // Refresh client validation time + const nowDate = new Date().toISOString(); + currentClient.credsValidationTime = nowDate; + const currentClientIndex = connection.findIndex( + (x) => x.brokerClientId === brokerClientId && x.role === role, + ); + if (currentClientIndex > -1) { + connection[currentClientIndex] = currentClient; + return res.status(201).send('OK'); + } else { + return res.status(500).send('Unable to find client connection.'); + } + } else { + logger.debug( + { identifier, brokerClientId, role, credentials }, + 'Invalid credentials - Creds check response returned false', + ); + currentClient.socket!.end(); + return res.status(401).send('Invalid credentials.'); + } + } +}; diff --git a/lib/server/routesHandlers/connectionStatusHandler.ts b/lib/server/routesHandlers/connectionStatusHandler.ts index 50529bffa..c6bb181e6 100644 --- a/lib/server/routesHandlers/connectionStatusHandler.ts +++ b/lib/server/routesHandlers/connectionStatusHandler.ts @@ -11,7 +11,7 @@ export const connectionStatusHandler = async (req: Request, res: Response) => { const desensitizedToken = getDesensitizedToken(token); const connections = getSocketConnections(); if (connections.has(token)) { - const clientsMetadata = connections.get(req.params.token).map((conn) => ({ + const clientsMetadata = connections.get(req.params.token)!.map((conn) => ({ version: conn.metadata && conn.metadata.version, filters: conn.metadata && conn.metadata.filters, })); diff --git a/lib/server/routesHandlers/httpRequestHandler.ts b/lib/server/routesHandlers/httpRequestHandler.ts index 699d53dc0..257a8d20d 100644 --- a/lib/server/routesHandlers/httpRequestHandler.ts +++ b/lib/server/routesHandlers/httpRequestHandler.ts @@ -66,12 +66,14 @@ export const overloadHttpRequestWithConnectionDetailsMiddleware = async ( // Grab a first (newest) client from the pool // This is really silly... - res.locals.websocket = connections.get(token)[0].socket; - res.locals.socketVersion = connections.get(token)[0].socketVersion; - res.locals.capabilities = connections.get(token)[0].metadata.capabilities; + res.locals.websocket = connections.get(token)![0].socket; + res.locals.socketVersion = connections.get(token)![0].socketVersion; + res.locals.capabilities = connections.get(token)![0].metadata.capabilities; + res.locals.brokerAppClientId = + connections.get(token)![0].brokerAppClientId ?? ''; req['locals'] = {}; req['locals']['capabilities'] = - connections.get(token)[0].metadata.capabilities; + connections.get(token)![0].metadata.capabilities; // strip the leading url req.url = req.url.slice(`/broker/${token}`.length); if (req.url.includes('connection_role')) { diff --git a/lib/server/routesHandlers/postResponseHandler.ts b/lib/server/routesHandlers/postResponseHandler.ts index fcbbc3cdd..7ea67813a 100644 --- a/lib/server/routesHandlers/postResponseHandler.ts +++ b/lib/server/routesHandlers/postResponseHandler.ts @@ -4,6 +4,8 @@ import { log as logger } from '../../logs/logger'; import { getDesensitizedToken } from '../utils/token'; import { incrementHttpRequestsTotal } from '../../common/utils/metrics'; import { StreamResponseHandler } from '../../hybrid-sdk/http/server-post-stream-handler'; +import { getConfig } from '../../common/config/config'; +import { decode } from 'jsonwebtoken'; export const handlePostResponse = (req: Request, res: Response) => { incrementHttpRequestsTotal(false, 'data-response'); @@ -32,6 +34,35 @@ export const handlePostResponse = (req: Request, res: Response) => { .json({ message: 'unable to find request matching streaming id' }); return; } + if (getConfig().BROKER_SERVER_MANDATORY_AUTH_ENABLED) { + const credentials = req.headers.authorization; + if (!credentials) { + logger.error( + logContext, + 'Invalid Broker Client credentials on response data', + ); + res.status(401).json({ message: 'Invalid Broker Client credentials' }); + return; + } + const decodedJwt = credentials + ? decode(credentials!.replace(/bearer /i, ''), { + complete: true, + }) + : null; + + const brokerAppClientId = decodedJwt ? decodedJwt?.payload['azp'] : ''; + if ( + !brokerAppClientId || + brokerAppClientId != streamHandler.streamResponse.brokerAppClientId + ) { + logger.error( + logContext, + 'Invalid Broker Client credentials for stream on response data', + ); + res.status(401).json({ message: 'Invalid Broker Client credentials' }); + return; + } + } let statusAndHeaders = ''; let statusAndHeadersSize = -1; diff --git a/lib/server/socket.ts b/lib/server/socket.ts index 91c45c814..914dd2f40 100644 --- a/lib/server/socket.ts +++ b/lib/server/socket.ts @@ -5,15 +5,32 @@ import { SocketHandler } from './types/socket'; import { handleIoError } from './socketHandlers/errorHandler'; import { handleSocketConnection } from './socketHandlers/connectionHandler'; import { initConnectionHandler } from './socketHandlers/initHandlers'; -// import { maskToken } from '../common/utils/token'; -// import { log as logger } from '../logs/logger'; +import { log as logger } from '../logs/logger'; +import { maskToken } from '../common/utils/token'; +import { validateBrokerClientCredentials } from './auth/authHelpers'; +import { Role } from '../client/types/client'; +import { decode } from 'jsonwebtoken'; -const socketConnections = new Map(); +export interface ClientSocket { + socket?: { end() }; + socketType: 'server'; + socketVersion: number; + brokerClientId: string; + brokerAppClientId: string; + role: Role; + metadata?: any; + credsValidationTime?: string; +} +const socketConnections = new Map(); export const getSocketConnections = () => { return socketConnections; }; +export const getSocketConnectionByIdentifier = (identifier: string) => { + return socketConnections.get(identifier); +}; + const socket = ({ server, loadedServerOpts }): SocketHandler => { const ioConfig = { transformer: 'engine.io', @@ -30,54 +47,94 @@ const socket = ({ server, loadedServerOpts }): SocketHandler => { }; const websocket = new Primus(server, ioConfig); - // websocket.authorize(async (req, done) => { - // const maskedToken = maskToken( - // req.uri.pathname.replaceAll(/^\/primus\/([^/]+)\//g, '$1').toLowerCase(), - // ); - // const authHeader = req.headers['authorization']; - - // if ( - // (!authHeader || !authHeader.startsWith('Bearer')) && - // loadedServerOpts.config.BROKER_SERVER_MANDATORY_AUTH_ENABLED - // ) { - // logger.error({ maskedToken }, 'request missing Authorization header'); - // done({ - // statusCode: 401, - // authenticate: 'Bearer', - // message: 'missing required authorization header', - // }); - // return; - // } + if (loadedServerOpts.config.BROKER_SERVER_MANDATORY_AUTH_ENABLED) { + websocket.authorize(async (req, done) => { + const connectionIdentifier = req.uri.pathname + .replaceAll(/^\/primus\/([^/]+)\//g, '$1') + .toLowerCase(); + const maskedToken = maskToken(connectionIdentifier); + const authHeader = + req.headers['Authorization'] ?? req.headers['authorization']; + const brokerClientId = req.headers['x-snyk-broker-client-id'] ?? null; + const role = req.headers['x-snyk-broker-client-role'] ?? null; + if ( + (!authHeader || + !authHeader.toLowerCase().startsWith('bearer') || + !brokerClientId) && + loadedServerOpts.config.BROKER_SERVER_MANDATORY_AUTH_ENABLED + ) { + logger.debug({ maskedToken }, 'request missing Authorization header'); + done({ + statusCode: 401, + authenticate: 'Bearer', + message: 'missing required authorization header', + }); + return; + } - // const jwt = authHeader - // ? authHeader.substring(authHeader.indexOf(' ') + 1) - // : ''; - // if (!jwt) logger.debug({}, `TODO: Validate jwt`); - // done(); - // // let oauthResponse = await axiosInstance.request({ - // // url: 'http://localhost:8080/oauth2/introspect', - // // method: 'POST', - // // headers: { - // // 'Content-Type': 'application/x-www-form-urlencoded', - // // }, - // // auth: { - // // username: 'broker-connection-a', - // // password: 'secret', - // // }, - // // data: `token=${token}`, - // // }); + const jwt = authHeader + ? authHeader.substring(authHeader.indexOf(' ') + 1) + : ''; + if ( + !jwt && + loadedServerOpts.config.BROKER_SERVER_MANDATORY_AUTH_ENABLED + ) { + done({ + statusCode: 401, + authenticate: 'Bearer', + message: 'Invalid JWT', + }); + return; + } else { + logger.debug( + { maskedToken: maskToken(connectionIdentifier), brokerClientId }, + `Validating auth for connection ${connectionIdentifier} client Id ${brokerClientId}, role ${role}`, + ); + const credsCheckResponse = await validateBrokerClientCredentials( + jwt, + brokerClientId, + connectionIdentifier, + ); + if (!credsCheckResponse) { + done({ + statusCode: 401, + authenticate: 'Bearer', + message: 'Invalid credentials.', + }); + } - // // if (!oauthResponse.data.active) { - // // logger.error({maskedToken}, 'JWT is not active (could be expired, malformed, not issued by us, etc)'); - // // done({ - // // statusCode: 403, - // // message: 'token not active', - // // }); - // // } else { - // // req.oauth_data = oauthResponse.data; - // // done(); - // // } - // }); + const decodedJwt = decode(jwt, { complete: true }); + const brokerAppClientId = decodedJwt?.payload['azp'] ?? ''; + const nowDate = new Date().toISOString(); + const currentClient: ClientSocket = { + socketType: 'server', + socketVersion: 1, + brokerClientId: brokerClientId, + brokerAppClientId: brokerAppClientId, + role: role ?? Role.primary, + credsValidationTime: nowDate, + }; + const connections = getSocketConnections(); + const clientPool = + (connections.get(connectionIdentifier) as Array) || []; + const currentClientIndex = clientPool.findIndex( + (x) => + x.brokerClientId === currentClient.brokerClientId && + x.role === currentClient.role, + ); + if (currentClientIndex < 0) { + clientPool.unshift(currentClient); + } else { + clientPool[currentClientIndex] = { + ...clientPool[currentClientIndex], + ...currentClient, + }; + } + connections.set(connectionIdentifier, clientPool); + } + done(); + }); + } websocket.socketType = 'server'; websocket.socketVersion = 1; websocket.plugin('emitter', Emitter); diff --git a/lib/server/socketHandlers/closeHandler.ts b/lib/server/socketHandlers/closeHandler.ts index 1859006b5..da0a2dba4 100644 --- a/lib/server/socketHandlers/closeHandler.ts +++ b/lib/server/socketHandlers/closeHandler.ts @@ -19,7 +19,7 @@ export const handleConnectionCloseOnSocket = ( .get(token) ?.filter((_) => _.socket !== socket); const filteredClientPool = - clientPool?.filter((_) => _.socket !== socket) || ''; + clientPool?.filter((_) => _.socket !== socket) || []; logger.info( { closeReason, diff --git a/lib/server/socketHandlers/identifyHandler.ts b/lib/server/socketHandlers/identifyHandler.ts index 214a674e0..e3c4ae929 100644 --- a/lib/server/socketHandlers/identifyHandler.ts +++ b/lib/server/socketHandlers/identifyHandler.ts @@ -73,14 +73,30 @@ export const handleIdentifyOnSocket = (clientData, socket, token): boolean => { }, 'new client connection identified', ); - const connections = getSocketConnections(); - const clientPool = connections.get(token) || []; - clientPool.unshift({ + const currentClient = { socket, socketType: 'server', socketVersion: 1, metadata: clientData.metadata, - }); + brokerClientId: clientData.metadata.clientId, + }; + const connections = getSocketConnections(); + const clientPool = (connections.get(token) as Array) || []; + const currentClientIndex = clientPool.findIndex( + (x) => + clientData.metadata.clientId && + x.brokerClientId === clientData.metadata.clientId && + clientData.metadata.role && + x.role === clientData.metadata.role, + ); + if (currentClientIndex < 0) { + clientPool.unshift(currentClient); + } else { + clientPool[currentClientIndex] = { + ...clientPool[currentClientIndex], + ...currentClient, + }; + } connections.set(token, clientPool); socket.on('chunk', streamingResponse(token)); diff --git a/package.json b/package.json index a4fd304ff..c115789f2 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,11 @@ "prepare": "npm run build && rm -rf ./dist/client-templates && cp -Rf ./client-templates ./dist", "start": "node .", "dev": "tsc-watch --project tsconfig.json --onSuccess 'node .' | ./node_modules/.bin/bunyan", - "dev:client": "tsc-watch --project tsconfig.json --onSuccess 'node dist/cli/index.js client' | ./node_modules/.bin/bunyan", + "dev:client": "LOG_LEVEL=debug PORT=9001 NODE_ENV=development tsc-watch --project tsconfig.json --onSuccess 'node dist/cli/index.js client' | ./node_modules/.bin/bunyan", + "dev:client-to-local-server": "USE_LOCAL_BACKEND='true' LOG_LEVEL=debug PORT=9001 NODE_ENV=development tsc-watch --project tsconfig.json --onSuccess 'node dist/cli/index.js client' | ./node_modules/.bin/bunyan", + "dev:client2-to-local-server": "USE_LOCAL_BACKEND='true' LOG_LEVEL=debug PORT=9002 NODE_ENV=development tsc-watch --project tsconfig.json --onSuccess 'node dist/cli/index.js client' | ./node_modules/.bin/bunyan", + "dev:server": "LOG_LEVEL=debug PORT=9000 ACCEPT=accept-server.local.json NODE_ENV=development tsc-watch --project tsconfig.json --onSuccess 'node dist/cli/index.js server' | ./node_modules/.bin/bunyan", + "dev:server-with-auth": "BROKER_SERVER_MANDATORY_AUTH_ENABLED=true npm run dev:server", "test": "npm run test:unit && npm run test:functional", "test:unit": "jest unit --detectOpenHandles", "test:functional": "jest functional --detectOpenHandles --runInBand", diff --git a/test/functional/server-client-universal-bearer-auth.test.ts b/test/functional/server-client-universal-bearer-auth.test.ts index 1217aa8e6..a1b6182b9 100644 --- a/test/functional/server-client-universal-bearer-auth.test.ts +++ b/test/functional/server-client-universal-bearer-auth.test.ts @@ -28,9 +28,9 @@ describe('proxy requests originating from behind the broker server', () => { beforeAll(async () => { const PORT = 9999; tws = await createTestWebServer(); - + process.env.RESPONSE_DATA_HIDDEN_ENABLED = 'true'; bs = await createBrokerServer({ filters: serverAccept, port: PORT }); - + process.env.API_BASE_URL = `http://localhost:${bs.port}`; process.env.SNYK_BROKER_SERVER_UNIVERSAL_CONFIG_ENABLED = 'true'; process.env.UNIVERSAL_BROKER_ENABLED = 'true'; process.env.SERVICE_ENV = 'universaltest7'; diff --git a/test/functional/server-client-universal-pooled-credentials.test.ts b/test/functional/server-client-universal-pooled-credentials.test.ts index 2b2b07cbb..2e87f29d8 100644 --- a/test/functional/server-client-universal-pooled-credentials.test.ts +++ b/test/functional/server-client-universal-pooled-credentials.test.ts @@ -33,9 +33,9 @@ describe('proxy requests originating from behind the broker server with pooled c const PORT = 9999; tws = await createTestWebServer(); - + process.env.RESPONSE_DATA_HIDDEN_ENABLED = 'true'; bs = await createBrokerServer({ port: PORT, filters: serverAccept }); - + process.env.API_BASE_URL = `http://localhost:${bs.port}`; process.env.SNYK_BROKER_SERVER_UNIVERSAL_CONFIG_ENABLED = 'true'; process.env.UNIVERSAL_BROKER_ENABLED = 'true'; process.env.SERVICE_ENV = 'universaltestpool'; diff --git a/test/functional/server-client-universal.test.ts b/test/functional/server-client-universal.test.ts index 6da64569a..a75f90468 100644 --- a/test/functional/server-client-universal.test.ts +++ b/test/functional/server-client-universal.test.ts @@ -28,10 +28,11 @@ describe('proxy requests originating from behind the broker server', () => { beforeAll(async () => { const PORT = 9999; tws = await createTestWebServer(); - + process.env.RESPONSE_DATA_HIDDEN_ENABLED = 'true'; bs = await createBrokerServer({ filters: serverAccept, port: PORT }); process.env.SNYK_BROKER_SERVER_UNIVERSAL_CONFIG_ENABLED = 'true'; + process.env.API_BASE_URL = `http://localhost:${bs.port}`; process.env.UNIVERSAL_BROKER_ENABLED = 'true'; process.env.SERVICE_ENV = 'universaltest'; process.env.BROKER_TOKEN_1 = 'brokertoken1';