Skip to content

Commit

Permalink
feat(deps): allow applying useSystemCA to OIDC IdP MONGOSH-1712 (#1868
Browse files Browse the repository at this point in the history
)
  • Loading branch information
addaleax authored Mar 11, 2024
1 parent 98157a8 commit 893faf4
Show file tree
Hide file tree
Showing 10 changed files with 718 additions and 154 deletions.
728 changes: 600 additions & 128 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/arg-parser/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
"mongodb-connection-string-url": "^3.0.0"
},
"devDependencies": {
"@mongodb-js/devtools-connect": "^2.4.4",
"@mongodb-js/devtools-connect": "^2.6.0",
"@mongodb-js/eslint-config-mongosh": "^1.0.0",
"@mongodb-js/prettier-config-devtools": "^1.0.1",
"@mongodb-js/tsconfig-mongosh": "^1.0.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/e2e-tests/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
},
"devDependencies": {
"@mongodb-js/eslint-config-mongosh": "^1.0.0",
"@mongodb-js/oidc-mock-provider": "^0.3.0",
"@mongodb-js/oidc-mock-provider": "^0.9.0",
"@mongodb-js/prettier-config-devtools": "^1.0.1",
"@mongodb-js/tsconfig-mongosh": "^1.0.0",
"@types/chai-as-promised": "^7.1.3",
Expand Down
102 changes: 94 additions & 8 deletions packages/e2e-tests/test/e2e-oidc.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@ import {
skipIfApiStrict,
skipIfEnvServerVersion,
} from '../../../testing/integration-testing-hooks';
import { promises as fs } from 'fs';
import type { OIDCMockProviderConfig } from '@mongodb-js/oidc-mock-provider';
import { OIDCMockProvider } from '@mongodb-js/oidc-mock-provider';
import { TestShell } from './test-shell';
import path from 'path';
import { expect } from 'chai';
import { createServer as createHTTPSServer } from 'https';
import { getCertPath, useTmpdir } from './repl-helpers';

describe('OIDC auth e2e', function () {
skipIfApiStrict(); // connectionStatus is unversioned.
Expand All @@ -18,7 +21,9 @@ describe('OIDC auth e2e', function () {
let testServer2: MongoRunnerSetup;
let oidcMockProviderConfig: OIDCMockProviderConfig;
let oidcMockProvider: OIDCMockProvider;
let oidcMockProviderHttps: OIDCMockProvider;
let shell: TestShell;
const tmpdir = useTmpdir();

const fetchBrowserFixture = `"${path.resolve(
__dirname,
Expand Down Expand Up @@ -53,7 +58,24 @@ describe('OIDC auth e2e', function () {
return getTokenPayload(metadata);
},
};
oidcMockProvider = await OIDCMockProvider.create(oidcMockProviderConfig);
const httpsServerKeyCertBundle = await fs.readFile(
getCertPath('server.bundle.pem')
);
[oidcMockProvider, oidcMockProviderHttps] = await Promise.all([
OIDCMockProvider.create(oidcMockProviderConfig),
OIDCMockProvider.create({
...oidcMockProviderConfig,
createHTTPServer(requestListener) {
return createHTTPSServer(
{
key: httpsServerKeyCertBundle,
cert: httpsServerKeyCertBundle,
},
requestListener
);
},
}),
]);
const serverOidcConfig = {
issuer: oidcMockProvider.issuer,
clientId: 'testServer',
Expand All @@ -69,18 +91,30 @@ describe('OIDC auth e2e', function () {
'--setParameter',
'enableTestCommands=true',
];
testServer = new MongoRunnerSetup('e2e-oidc', {
testServer = new MongoRunnerSetup('e2e-oidc-test1', {
args: [
'--setParameter',
`oidcIdentityProviders=${JSON.stringify([serverOidcConfig])}`,
...commonOidcServerArgs,
],
});
testServer2 = new MongoRunnerSetup('e2e-oidc', {
testServer2 = new MongoRunnerSetup('e2e-oidc-test2', {
args: [
'--setParameter',
`oidcIdentityProviders=${JSON.stringify([
{ ...serverOidcConfig, clientId: 'testServer2' },
{
...serverOidcConfig,
clientId: 'testServer2',
matchPattern: '^testuser$',
authNamePrefix: 'dev',
},
{
...serverOidcConfig,
clientId: 'testServer2',
matchPattern: '^httpsIdPtestuser$',
authNamePrefix: 'https',
issuer: oidcMockProviderHttps.issuer,
},
])}`,
...commonOidcServerArgs,
],
Expand Down Expand Up @@ -110,6 +144,7 @@ describe('OIDC auth e2e', function () {
testServer?.stop(),
testServer2?.stop(),
oidcMockProvider?.close(),
oidcMockProviderHttps?.close(),
]);
});

Expand Down Expand Up @@ -245,9 +280,10 @@ describe('OIDC auth e2e', function () {
});

it('re-authenticates when connecting to a different endpoint from the same shell', async function () {
const urlOptions = { username: 'testuser' }; // Make sure these match between the two connections
shell = TestShell.start({
args: [
await testServer.connectionString(),
await testServer.connectionString({}, urlOptions),
'--authenticationMechanism=MONGODB-OIDC',
'--oidcRedirectUri=http://localhost:0/',
`--browser=${fetchBrowserFixture}`,
Expand All @@ -256,9 +292,12 @@ describe('OIDC auth e2e', function () {
await shell.waitForPrompt();

await verifyUser(shell, 'testuser', 'testServer-group');
const cs2 = await testServer2.connectionString({
authMechanism: 'MONGODB-OIDC',
});
const cs2 = await testServer2.connectionString(
{
authMechanism: 'MONGODB-OIDC',
},
urlOptions
);
await shell.executeLine(`db = connect(${JSON.stringify(cs2)})`);
await verifyUser(shell, 'testuser', 'testServer2-group');
shell.assertNoErrors();
Expand Down Expand Up @@ -313,4 +352,51 @@ describe('OIDC auth e2e', function () {
shell.assertNoErrors();
shell2.assertNoErrors();
});

it('can apply --useSystemCA to the IdP https endpoint', async function () {
await fs.mkdir(path.join(tmpdir.path, 'certs'), { recursive: true });
await fs.copyFile(
getCertPath('ca.crt'),
path.join(tmpdir.path, 'certs', 'somefilename.crt')
);

shell = TestShell.start({
args: [
await testServer2.connectionString(
{},
{ username: 'httpsIdPtestuser' }
),
'--authenticationMechanism=MONGODB-OIDC',
'--oidcRedirectUri=http://localhost:0/',
`--browser=${fetchBrowserFixture}`,
'--tlsUseSystemCA',
],
env: {
...process.env,
SSL_CERT_DIR: path.join(tmpdir.path, 'certs') + '',
MONGOSH_E2E_TEST_CURL_ALLOW_INVALID_TLS: '1',
},
});
await shell.waitForExit();
// We cannot make the mongod server accept the mock IdP's certificate,
// so the best we can verify here is that auth failed *on the server*
shell.assertContainsOutput(/MongoServerError: Authentication failed/);

// Negative test: Without --tlsUseSystemCA, mongosh fails earlier:
shell = TestShell.start({
args: [
await testServer2.connectionString(
{},
{ username: 'httpsIdPtestuser' }
),
'--authenticationMechanism=MONGODB-OIDC',
'--oidcRedirectUri=http://localhost:0/',
`--browser=${fetchBrowserFixture}`,
],
});
await shell.waitForExit();
shell.assertContainsOutput(
/Unable to fetch issuer metadata for "https:\/\/localhost:\d+"/
);
});
});
12 changes: 1 addition & 11 deletions packages/e2e-tests/test/e2e-tls.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
useTmpdir,
setTemporaryHomeDirectory,
readReplLogfile,
getCertPath,
} from './repl-helpers';
import { TestShell } from './test-shell';

Expand All @@ -26,17 +27,6 @@ async function connectionStringWithLocalhost(
return cs.toString();
}

function getCertPath(filename: string): string {
return path.join(
__dirname,
'..',
'..',
'..',
'testing',
'certificates',
filename
);
}
const CA_CERT = getCertPath('ca.crt');
const NON_CA_CERT = getCertPath('non-ca.crt');
const CLIENT_CERT = getCertPath('client.bundle.pem');
Expand Down
5 changes: 4 additions & 1 deletion packages/e2e-tests/test/fixtures/curl.mjs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
#!/usr/bin/env node
'use strict';
import fetch from 'node-fetch';

if (process.env.MONGOSH_E2E_TEST_CURL_ALLOW_INVALID_TLS) {
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
}

// fetch() an URL and ignore the response body
(async function () {
(await fetch(process.argv[2])).body?.resume();
Expand Down
13 changes: 13 additions & 0 deletions packages/e2e-tests/test/repl-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,23 @@ const setTemporaryHomeDirectory = () => {
return { homedir, env };
};

function getCertPath(filename: string): string {
return path.join(
__dirname,
'..',
'..',
'..',
'testing',
'certificates',
filename
);
}

// eslint-disable-next-line mocha/no-exports
export {
useTmpdir,
readReplLogfile,
fakeExternalEditor,
setTemporaryHomeDirectory,
getCertPath,
};
2 changes: 1 addition & 1 deletion packages/logging/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"node": ">=14.15.1"
},
"dependencies": {
"@mongodb-js/devtools-connect": "^2.4.4",
"@mongodb-js/devtools-connect": "^2.6.0",
"@mongosh/errors": "0.0.0-dev.0",
"@mongosh/history": "0.0.0-dev.0",
"@mongosh/types": "0.0.0-dev.0",
Expand Down
4 changes: 2 additions & 2 deletions packages/service-provider-server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@
}
},
"dependencies": {
"@mongodb-js/devtools-connect": "^2.4.4",
"@mongodb-js/oidc-plugin": "^0.3.1",
"@mongodb-js/devtools-connect": "^2.6.0",
"@mongodb-js/oidc-plugin": "^0.4.0",
"@mongosh/errors": "0.0.0-dev.0",
"@mongosh/service-provider-core": "0.0.0-dev.0",
"@mongosh/types": "0.0.0-dev.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/types/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
"unitTestsOnly": true
},
"dependencies": {
"@mongodb-js/devtools-connect": "^2.4.3"
"@mongodb-js/devtools-connect": "^2.6.0"
},
"devDependencies": {
"@mongodb-js/eslint-config-mongosh": "^1.0.0",
Expand Down

0 comments on commit 893faf4

Please sign in to comment.