Skip to content

Commit

Permalink
fix: Authentication when a pre-existing invalid token is stored [HEAD…
Browse files Browse the repository at this point in the history
…-1197] (#4994)


---------

Co-authored-by: Avishagp <avishag.israeli@snyk.io>
  • Loading branch information
PeterSchafer and Avishagp committed Jan 17, 2024
1 parent 8f1ff94 commit 2890b46
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 39 deletions.
2 changes: 1 addition & 1 deletion src/lib/is-ci.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const ciEnvs = new Set([
export const ciEnvs = new Set([
'SNYK_CI',
'CI',
'CONTINUOUS_INTEGRATION',
Expand Down
28 changes: 28 additions & 0 deletions test/acceptance/config-helper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { runSnykCLI } from '../jest/util/runSnykCLI';

export async function getCliConfig(): Promise<Record<string, string>> {
let initialConfig: Record<string, string> = {};
const { stdout } = await runSnykCLI('config');
if (stdout) {
initialConfig = stdout
.trim()
.split('\n')
.reduce((acc, line) => {
const [key, value] = line.split(': ');
return {
...acc,
[key]: value,
};
}, {});
}
return initialConfig;
}

export async function restoreCliConfig(config: Record<string, string>) {
await runSnykCLI('config clear');
if (Object.keys(config).length > 0) {
for (const key in config) {
await runSnykCLI(`config set ${key}=${config[key]}`);
}
}
}
60 changes: 48 additions & 12 deletions test/acceptance/fake-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import * as fs from 'fs';
import * as http from 'http';
import * as https from 'https';
import * as path from 'path';
import * as net from 'net';
import { getFixturePath } from '../jest/util/getFixturePath';
import * as os from 'os';

const featureFlagDefaults = (): Map<string, boolean> => {
return new Map([
Expand All @@ -14,6 +16,23 @@ const featureFlagDefaults = (): Map<string, boolean> => {
]);
};

export function getFirstIPv4Address(): string {
let ipaddress = '';

const interfaces = os.networkInterfaces();
for (const [, group] of Object.entries(interfaces)) {
if (group) {
for (const inter of group) {
if (inter && inter.family == 'IPv4' && inter.address != '127.0.0.1') {
ipaddress = inter.address;
break;
}
}
}
}
return ipaddress;
}

export type FakeServer = {
getRequests: () => express.Request[];
popRequest: () => express.Request;
Expand Down Expand Up @@ -49,6 +68,7 @@ export const fakeServer = (basePath: string, snykToken: string): FakeServer => {
let nextResponse: any = undefined;
let depGraphResponse: Record<string, unknown> | undefined = undefined;
let server: http.Server | undefined = undefined;
const sockets = new Set();

const restore = () => {
statusCode = undefined;
Expand Down Expand Up @@ -119,18 +139,20 @@ export const fakeServer = (basePath: string, snykToken: string): FakeServer => {

[basePath + '/verify/callback', basePath + '/verify/token'].map((url) => {
app.post(url, (req, res) => {
if (req.body.api === snykToken) {
return res.send({
ok: true,
api: snykToken,
});
}

if (req.body.token) {
return res.send({
ok: true,
api: snykToken,
});
if (req.header('Authorization') === undefined) {
if (req.body.api === snykToken) {
return res.send({
ok: true,
api: snykToken,
});
}

if (req.body.token) {
return res.send({
ok: true,
api: snykToken,
});
}
}

res.status(401);
Expand All @@ -140,6 +162,11 @@ export const fakeServer = (basePath: string, snykToken: string): FakeServer => {
});
});

app.get('/login', (req, res) => {
res.status(200);
res.send('Test Authenticated!');
});

app.use((req, res, next) => {
if (
req.url?.includes('/iac-org-settings') ||
Expand Down Expand Up @@ -593,6 +620,10 @@ export const fakeServer = (basePath: string, snykToken: string): FakeServer => {
const listenPromise = (port: string | number) => {
return new Promise<void>((resolve) => {
server = http.createServer(app).listen(Number(port), resolve);

server?.on('connection', (socket) => {
sockets.add(socket);
});
});
};

Expand Down Expand Up @@ -628,6 +659,11 @@ export const fakeServer = (basePath: string, snykToken: string): FakeServer => {
};

const close = (callback: () => void) => {
for (const socket of sockets) {
(socket as net.Socket)?.destroy();
sockets.delete(socket);
}

closePromise().then(callback);
};

Expand Down
51 changes: 44 additions & 7 deletions test/jest/acceptance/auth.spec.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,47 @@
import { fakeServer } from '../../acceptance/fake-server';
import { fakeServer, getFirstIPv4Address } from '../../acceptance/fake-server';
import { runSnykCLI } from '../util/runSnykCLI';
import { getCliConfig, restoreCliConfig } from '../../acceptance/config-helper';
import { ciEnvs } from '../../../src/lib/is-ci';

jest.setTimeout(1000 * 60);

describe('Auth', () => {
let server: ReturnType<typeof fakeServer>;
let env: Record<string, string>;
let initialConfig: Record<string, string> = {};
const serverToken = 'random';

beforeAll((done) => {
const apiPath = '/api/v1';
const apiPort = process.env.PORT || process.env.SNYK_PORT || '12345';
env = {
...process.env,
SNYK_API: 'http://localhost:' + apiPort + apiPath,
SNYK_API: 'http://' + getFirstIPv4Address() + ':' + apiPort + apiPath,
SNYK_DISABLE_ANALYTICS: '1',
SNYK_HTTP_PROTOCOL_UPGRADE: '0',
};

server = fakeServer(apiPath, env.SNYK_TOKEN);
server.listen(apiPort, () => done());
});
ciEnvs.forEach((value) => {
delete env[value];
});

afterEach(() => {
server.restore();
server = fakeServer(apiPath, serverToken);
server.listen(apiPort, () => done());
});

afterAll((done) => {
server.close(() => done());
});

beforeEach(async () => {
initialConfig = await getCliConfig();
});

afterEach(async () => {
server.restore();
await restoreCliConfig(initialConfig);
});

it('successfully uses oauth client credentials grant to authenticate', async () => {
const { code } = await runSnykCLI(
`auth --auth-type=oauth --client-id a --client-secret b`,
Expand All @@ -52,4 +66,27 @@ describe('Auth', () => {
);
expect(code).toEqual(2);
});

// Tests for existing token is invalid (for when config value is set incorrectly) config set api=invalid
it('ignore existing token when running auth', async () => {
const resultConfigSet = await runSnykCLI('config set api=invalid', {
env,
});
expect(resultConfigSet.code).toEqual(0);

// run command under test
const { code, stderr } = await runSnykCLI(`auth --auth-type=token -d`, {
env,
});

console.debug(stderr);

const resultConfigGet = await runSnykCLI('config get api', {
env,
});

expect(code).toEqual(0);
expect(resultConfigGet.code).toEqual(0);
expect(resultConfigGet.stdout).toContain(serverToken);
});
});
24 changes: 5 additions & 19 deletions test/jest/acceptance/https.spec.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,15 @@
import * as fs from 'fs';
import { fakeServer, FakeServer } from '../../acceptance/fake-server';
import {
fakeServer,
FakeServer,
getFirstIPv4Address,
} from '../../acceptance/fake-server';
import { createProjectFromWorkspace } from '../util/createProject';
import { getFixturePath } from '../util/getFixturePath';
import { runSnykCLI } from '../util/runSnykCLI';
import * as os from 'os';

jest.setTimeout(1000 * 30);

function getFirstIPv4Address(): string {
let ipaddress = '';

const interfaces = os.networkInterfaces();
for (const [, group] of Object.entries(interfaces)) {
if (group) {
for (const inter of group) {
if (inter && inter.family == 'IPv4' && inter.address != '127.0.0.1') {
ipaddress = inter.address;
break;
}
}
}
}
return ipaddress;
}

describe('https', () => {
let server: FakeServer;
let env: Record<string, string>;
Expand Down

0 comments on commit 2890b46

Please sign in to comment.