Skip to content

Commit

Permalink
fix(NODE-5548): ensure that tlsCertificateKeyFile maps to cert and key (
Browse files Browse the repository at this point in the history
#3819)

Co-authored-by: Durran Jordan <durran@gmail.com>
  • Loading branch information
W-A-James and durran committed Aug 22, 2023
1 parent bf00e32 commit a0955bd
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 6 deletions.
15 changes: 10 additions & 5 deletions src/mongo_client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -435,10 +435,14 @@ export class MongoClient extends TypedEventEmitter<MongoClientEvents> {

if (options.tls) {
if (typeof options.tlsCAFile === 'string') {
options.ca ??= await fs.readFile(options.tlsCAFile, { encoding: 'utf8' });
options.ca ??= await fs.readFile(options.tlsCAFile);
}
if (typeof options.tlsCertificateKeyFile === 'string') {
options.key ??= await fs.readFile(options.tlsCertificateKeyFile, { encoding: 'utf8' });
if (!options.key || !options.cert) {
const contents = await fs.readFile(options.tlsCertificateKeyFile);
options.key ??= contents;
options.cert ??= contents;
}
}
}
if (typeof options.srvHost === 'string') {
Expand Down Expand Up @@ -787,6 +791,7 @@ export interface MongoOptions
* |:----------------------|:----------------------------------------------|:-------------------|
* | `ca` | `tlsCAFile` | `string` |
* | `crl` | N/A | `string` |
* | `cert` | `tlsCertificateKeyFile` | `string` |
* | `key` | `tlsCertificateKeyFile` | `string` |
* | `passphrase` | `tlsCertificateKeyFilePassword` | `string` |
* | `rejectUnauthorized` | `tlsAllowInvalidCertificates` | `boolean` |
Expand All @@ -804,9 +809,9 @@ export interface MongoOptions
*
* The files specified by the paths passed in to the `tlsCAFile` and `tlsCertificateKeyFile` fields
* are read lazily on the first call to `MongoClient.connect`. Once these files have been read and
* the `ca` and `key` fields are populated, they will not be read again on subsequent calls to
* `MongoClient.connect`. As a result, until the first call to `MongoClient.connect`, the `ca`
* and `key` fields will be undefined.
* the `ca`, `cert` and `key` fields are populated, they will not be read again on subsequent calls to
* `MongoClient.connect`. As a result, until the first call to `MongoClient.connect`, the `ca`,
* `cert` and `key` fields will be undefined.
*/
tls: boolean;

Expand Down
47 changes: 46 additions & 1 deletion test/manual/tls_support.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import { expect } from 'chai';
import { promises as fs } from 'fs';

import { LEGACY_HELLO_COMMAND, MongoClient, type MongoClientOptions } from '../mongodb';
import {
LEGACY_HELLO_COMMAND,
MongoClient,
type MongoClientOptions,
MongoServerSelectionError
} from '../mongodb';

const REQUIRED_ENV = ['MONGODB_URI', 'SSL_KEY_FILE', 'SSL_CA_FILE'];

Expand Down Expand Up @@ -51,11 +56,13 @@ describe('TLS Support', function () {
expect(client.options).property('tlsCertificateKeyFile', TLS_CERT_KEY_FILE);
expect(client.options).not.have.property('ca');
expect(client.options).not.have.property('key');
expect(client.options).not.have.property('cert');

await client.connect();

expect(client.options).property('ca').to.exist;
expect(client.options).property('key').to.exist;
expect(client.options).property('cert').to.exist;
});

context('when client has been opened and closed more than once', function () {
Expand Down Expand Up @@ -106,6 +113,44 @@ describe('TLS Support', function () {
});
});
});

context('when tlsCertificateKeyFile is provided, but tlsCAFile is missing', () => {
let client: MongoClient;
beforeEach(() => {
client = new MongoClient(CONNECTION_STRING, {
tls: true,
tlsCertificateKeyFile: TLS_CERT_KEY_FILE,
serverSelectionTimeoutMS: 5000,
connectTimeoutMS: 5000
});
});
afterEach(async () => {
if (client) await client.close();
});

it('throws a MongoServerSelectionError', async () => {
const err = await client.connect().catch(e => e);
expect(err).to.be.instanceOf(MongoServerSelectionError);
});
});

context('when tlsCAFile is provided, but tlsCertificateKeyFile is missing', () => {
let client: MongoClient;
beforeEach(() => {
client = new MongoClient(CONNECTION_STRING, {
tls: true,
tlsCAFile: TLS_CA_FILE
});
});
afterEach(async () => {
if (client) await client.close();
});

it('connects without error', async () => {
const clientOrError = await client.connect().catch(e => e);
expect(clientOrError).to.be.instanceOf(MongoClient);
});
});
});

function makeConnectionTest(connectionString: string, clientOptions?: MongoClientOptions) {
Expand Down
1 change: 1 addition & 0 deletions test/unit/mongo_client.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ describe('MongoOptions', function () {
expect(options).to.not.have.property('tlsCertificateKeyFilePassword');
expect(options).to.not.have.property('key');
expect(options).to.not.have.property('ca');
expect(options).to.not.have.property('cert');
expect(options).to.have.property('tlsCertificateKeyFile', filename);
expect(options).to.have.property('tlsCAFile', filename);
expect(options).has.property('passphrase', 'tlsCertificateKeyFilePassword');
Expand Down

0 comments on commit a0955bd

Please sign in to comment.