Skip to content

Commit

Permalink
Merge pull request #850 from snyk/fix/universal-bearer-auth-conns
Browse files Browse the repository at this point in the history
fix: universal broker handle bearer-auth filters
  • Loading branch information
aarlaud authored Sep 27, 2024
2 parents 3ea95a2 + 89167b7 commit 55b1874
Show file tree
Hide file tree
Showing 9 changed files with 172 additions and 4 deletions.
2 changes: 1 addition & 1 deletion config.universaltest.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
"AZURE_REPOS_HOST":"${AZURE_REPOS_HOST}"
},
"my jira pat": {
"type": "jira-bearer-auth",
"type": "jira",
"id": "4",
"identifier": "${BROKER_TOKEN_4}",
"JIRA_PAT": "${JIRA_PAT}",
Expand Down
27 changes: 27 additions & 0 deletions config.universaltest7.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"BROKER_CLIENT_CONFIGURATION": {
"common": {
"default": {
"BROKER_SERVER_URL": "https://broker2.dev.snyk.io",
"BROKER_HA_MODE_ENABLED": "false",
"BROKER_DISPATCHER_BASE_URL": "https://api.dev.snyk.io"
}
},
"github": {
"validations":[{
"url": "https://notexists.notexists/no-such-url-ever"
}]
},
"gitlab": {
"validations":[{
"url": "https://notexists.notexists/no-such-url-ever"
}]
}
},
"CONNECTIONS": {
"my bitbucket-server-bearer-auth connection": {
"type": "bitbucket-server-bearer-auth",
"identifier": "${BROKER_TOKEN_1}"
}
}
}
8 changes: 7 additions & 1 deletion lib/client/routesHandler/websocketConnectionMiddlewares.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,13 @@ export const websocketConnectionSelectorMiddleware = (
availableConnectionsTypes.includes('github-cloud-app')
) {
inboundRequestType = 'github-cloud-app';
} else if (
splitUrl.length > 2 &&
splitUrl[2] == 'bitbucket-server' &&
!availableConnectionsTypes.includes('bitbucket-server') &&
availableConnectionsTypes.includes('bitbucket-server-bearer-auth')
) {
inboundRequestType = 'bitbucket-server-bearer-auth';
} else {
logger.warn({ url: req.path }, 'Unexpected type in webhook request');
res
Expand Down Expand Up @@ -89,7 +96,6 @@ export const websocketConnectionSelectorMiddleware = (
{ url: req.path },
'Unknown type in client->server request.',
);

if (config.serviceEnv == 'universaltest') {
// only to support testing, blocking all other unknown request types
inboundRequestType =
Expand Down
6 changes: 5 additions & 1 deletion lib/client/socket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { LoadedClientOpts } from '../common/types/options';
import { maskToken } from '../common/utils/token';
import { fetchJwt } from './auth/oauth';
import { getServerId } from './dispatcher';
import { determineFilterType } from './utils/filterSelection';

export const createWebSocketConnectionPairs = async (
websocketConnections: WebSocketConnection[],
Expand All @@ -38,7 +39,10 @@ export const createWebSocketConnectionPairs = async (
const integrationType =
clientOpts.config.connections[`${connectionKey}`].type;

socketIdentifyingMetadata.supportedIntegrationType = integrationType;
socketIdentifyingMetadata.supportedIntegrationType = determineFilterType(
integrationType,
clientOpts.config.connections[`${connectionKey}`],
);

if (!socketIdentifyingMetadata.identifier) {
throw new Error(
Expand Down
15 changes: 15 additions & 0 deletions lib/client/utils/filterSelection.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export const determineFilterType = (
type: string,
configObject: Record<any, string>,
) => {
if ('jira' === type && Object.keys(configObject).includes('JIRA_PAT')) {
return 'jira-bearer-auth';
}
if (
'bitbucket-server' === type &&
Object.keys(configObject).includes('BITBUCKET_PAT')
) {
return 'bitbucket-server-bearer-auth';
}
return type;
};
5 changes: 4 additions & 1 deletion lib/common/config/universal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { log as logger } from '../../logs/logger';
import { Config, ConnectionConfig } from '../../client/types/config';
import { expandPlaceholderValuesInFlatList, getConfig } from './config';
import { getPluginsConfig } from './pluginsConfig';
import { determineFilterType } from '../../client/utils/filterSelection';

export const getConfigForType = (type: string) => {
const config = getConfig();
Expand Down Expand Up @@ -30,7 +31,9 @@ export const getConfigForConnection = (key, config) => {
return {
...getConfigForType(config.connections[key].type),
...config.connections[key],
...getValidationConfigForType(config.connections[key].type),
...getValidationConfigForType(
determineFilterType(config.connections[key].type, config),
),
};
};
export const getValidationConfigForType = (type) => {
Expand Down
4 changes: 4 additions & 0 deletions test/fixtures/client/filters-webhook.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
{
"path": "/webhook/gitlab/:webhookId",
"method": "POST"
},
{
"path": "/webhook/bitbucket-server/:webhookId",
"method": "POST"
}
]
}
102 changes: 102 additions & 0 deletions test/functional/webhook-universal-bitbucket-server-bearer-auth.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
const PORT = 9999;
process.env.BROKER_SERVER_URL = `http://localhost:${PORT}`;
import path from 'path';
import { axiosClient } from '../setup/axios-client';
import {
BrokerClient,
closeBrokerClient,
waitForBrokerServerConnections,
} from '../setup/broker-client';
import {
BrokerServer,
closeBrokerServer,
createBrokerServer,
waitForUniversalBrokerClientsConnection,
} from '../setup/broker-server';
import { TestWebServer, createTestWebServer } from '../setup/test-web-server';
import { DEFAULT_TEST_WEB_SERVER_PORT } from '../setup/constants';
import { createUniversalBrokerClient } from '../setup/broker-universal-client';

const fixtures = path.resolve(__dirname, '..', 'fixtures');
const serverAccept = path.join(fixtures, 'server', 'filters-webhook.json');
const clientAccept = path.join(fixtures, 'client', 'filters-webhook.json');

describe('proxy requests originating from behind the broker client', () => {
let tws: TestWebServer;
let bs: BrokerServer;
let bc: BrokerClient;
process.env.API_BASE_URL = `http://localhost:${DEFAULT_TEST_WEB_SERVER_PORT}`;

beforeAll(async () => {
process.env.SKIP_REMOTE_CONFIG = 'true';
tws = await createTestWebServer();

bs = await createBrokerServer({ port: PORT, filters: serverAccept });

process.env.SNYK_BROKER_SERVER_UNIVERSAL_CONFIG_ENABLED = 'true';
process.env.UNIVERSAL_BROKER_ENABLED = 'true';
process.env.SERVICE_ENV = 'universaltest7';
process.env.BROKER_TOKEN_1 = 'brokertoken1';
// process.env.BROKER_TOKEN_2 = 'brokertoken2';
process.env.SNYK_BROKER_CLIENT_CONFIGURATION__common__default__BROKER_SERVER_URL = `http://localhost:${bs.port}`;
process.env['SNYK_FILTER_RULES_PATHS__bitbucket-server-bearer-auth'] =
clientAccept;
// process.env['SNYK_FILTER_RULES_PATHS__github-cloud-app'] = clientAccept;

bc = await createUniversalBrokerClient();
await waitForUniversalBrokerClientsConnection(bs, 1);
});

afterAll(async () => {
await tws.server.close();
await closeBrokerClient(bc);
await closeBrokerServer(bs);
delete process.env.BROKER_SERVER_URL;
});

it('server identifies self to client', async () => {
const serverMetadata = await waitForBrokerServerConnections(bc);
expect(serverMetadata.map((x) => x.brokertoken)).toEqual(
expect.arrayContaining(['brokertoken1']),
);
expect(serverMetadata.map((x) => x.capabilities)).toEqual(
expect.arrayContaining([['receive-post-streams']]),
);
});

it('successfully broker Bitbucket servers Webhook call via bitbucket-server-bearer-auth tunnel conn', async () => {
const response = await axiosClient.post(
`http://localhost:${bc.port}/webhook/bitbucket-server/12345678-1234-1234-1234-123456789abc`,
{ some: { example: 'json' } },
);

expect(response.status).toEqual(200);
expect(response.data).toStrictEqual('Received webhook via websocket');
});

it('successfully fails Webhook call without matching type', async () => {
const response = await axiosClient.post(
`http://localhost:${bc.port}/webhook/githubd/12345678-1234-1234-1234-000000000000`,
{ some: { example: 'json' } },
);

expect(response.status).toEqual(401);
expect(response.data).toStrictEqual(
'Unexpected type in webhook request, unable to forward to server.',
);
});

it('successfully fails Webhook call via API without matching type', async () => {
await closeBrokerServer(bs);

const response = await axiosClient.post(
`http://localhost:${bc.port}/webhook/githubd/12345678-1234-1234-1234-000000000000`,
{ some: { example: 'json' } },
);

expect(response.status).toEqual(401);
expect(response.data).toStrictEqual(
'Unexpected type in webhook request, unable to forward to server.',
);
});
});
7 changes: 7 additions & 0 deletions test/setup/test-web-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,13 @@ const applyEchoRoutes = (app: Express) => {
resp.send('Received webhook via API');
},
);
echoRouter.post(
'/webhook/bitbucket-server/12345678-1234-1234-1234-123456789abc',
(_: express.Request, resp: express.Response) => {
resp.status(200);
resp.send('Received webhook via websocket');
},
);

echoRouter.get('/test', (_: express.Request, resp: express.Response) => {
resp.status(200);
Expand Down

0 comments on commit 55b1874

Please sign in to comment.