Skip to content

Commit 3232bf2

Browse files
dariakpljhaywar
authored andcommitted
fix(NODE-3591): tlsCertificateKeyFile option does not default cert (#2979)
1 parent 9bd27f0 commit 3232bf2

File tree

4 files changed

+106
-16
lines changed

4 files changed

+106
-16
lines changed

src/connection_string.ts

+14-13
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ function getBoolean(name: string, value: unknown): boolean {
176176
const valueString = String(value).toLowerCase();
177177
if (TRUTHS.has(valueString)) return true;
178178
if (FALSEHOODS.has(valueString)) return false;
179-
throw new MongoParseError(`For ${name} Expected stringified boolean value, got: ${value}`);
179+
throw new MongoParseError(`Expected ${name} to be stringified boolean value, got: ${value}`);
180180
}
181181

182182
function getInt(name: string, value: unknown): number {
@@ -335,6 +335,19 @@ export function parseOptions(
335335
allOptions.set(key, values);
336336
}
337337

338+
if (allOptions.has('tlsCertificateKeyFile') && !allOptions.has('tlsCertificateFile')) {
339+
allOptions.set('tlsCertificateFile', allOptions.get('tlsCertificateKeyFile'));
340+
}
341+
342+
if (allOptions.has('tls') || allOptions.has('ssl')) {
343+
const tlsAndSslOpts = (allOptions.get('tls') || [])
344+
.concat(allOptions.get('ssl') || [])
345+
.map(getBoolean.bind(null, 'tls/ssl'));
346+
if (new Set(tlsAndSslOpts).size !== 1) {
347+
throw new MongoParseError('All values of tls/ssl must be the same.');
348+
}
349+
}
350+
338351
const unsupportedOptions = setDifference(
339352
allKeys,
340353
Array.from(Object.keys(OPTIONS)).map(s => s.toLowerCase())
@@ -384,18 +397,6 @@ export function parseOptions(
384397
mongoOptions.dbName = 'test';
385398
}
386399

387-
if (allOptions.has('tls')) {
388-
if (new Set(allOptions.get('tls')?.map(getBoolean)).size !== 1) {
389-
throw new MongoParseError('All values of tls must be the same.');
390-
}
391-
}
392-
393-
if (allOptions.has('ssl')) {
394-
if (new Set(allOptions.get('ssl')?.map(getBoolean)).size !== 1) {
395-
throw new MongoParseError('All values of ssl must be the same.');
396-
}
397-
}
398-
399400
checkTLSOptions(mongoOptions);
400401

401402
if (options.promiseLibrary) PromiseProvider.set(options.promiseLibrary);

src/mongo_client.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ export interface MongoClientOptions extends BSONSerializeOptions, SupportedNodeC
112112
ssl?: boolean;
113113
/** Specifies the location of a local TLS Certificate */
114114
tlsCertificateFile?: string;
115-
/** Specifies the location of a local .pem file that contains either the clients TLS/SSL certificate or the clients TLS/SSL certificate and key. */
115+
/** Specifies the location of a local .pem file that contains either the client's TLS/SSL certificate and key or only the client's TLS/SSL key when tlsCertificateFile is used to provide the certificate. */
116116
tlsCertificateKeyFile?: string;
117117
/** Specifies the password to de-crypt the tlsCertificateKeyFile. */
118118
tlsCertificateKeyFilePassword?: string;

test/unit/core/connection_string.test.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ describe('Connection String', function () {
136136
it('should validate non-equal tls values', function () {
137137
expect(() => parseOptions('mongodb://localhost/?tls=true&tls=false')).to.throw(
138138
MongoParseError,
139-
'All values of tls must be the same.'
139+
'All values of tls/ssl must be the same.'
140140
);
141141
});
142142
});

test/unit/mongo_client_options.test.js

+90-1
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ describe('MongoOptions', function () {
128128
ssl: true,
129129
sslPass: 'pass',
130130
sslValidate: true,
131-
tls: false,
131+
tls: true,
132132
tlsAllowInvalidCertificates: true,
133133
tlsAllowInvalidHostnames: true,
134134
tlsCertificateKeyFilePassword: 'tls-pass',
@@ -245,6 +245,18 @@ describe('MongoOptions', function () {
245245
expect(options).has.property('tls', false);
246246
});
247247

248+
it('ssl= can be used to set tls=true', function () {
249+
const options = parseOptions('mongodb+srv://server.example.com/?ssl=true');
250+
expect(options).has.property('srvHost', 'server.example.com');
251+
expect(options).has.property('tls', true);
252+
});
253+
254+
it('tls= can be used to set tls=true', function () {
255+
const options = parseOptions('mongodb+srv://server.example.com/?tls=true');
256+
expect(options).has.property('srvHost', 'server.example.com');
257+
expect(options).has.property('tls', true);
258+
});
259+
248260
it('supports ReadPreference option in url', function () {
249261
const options = parseOptions('mongodb://localhost/?readPreference=nearest');
250262
expect(options.readPreference).to.be.an.instanceof(ReadPreference);
@@ -366,6 +378,83 @@ describe('MongoOptions', function () {
366378
expect(optionsUndefined.checkServerIdentity).to.equal(undefined);
367379
});
368380

381+
describe('[tls certificate handling]', () => {
382+
before(() => {
383+
fs.writeFileSync('testCertKey.pem', 'cert key');
384+
fs.writeFileSync('testKey.pem', 'test key');
385+
fs.writeFileSync('testCert.pem', 'test cert');
386+
});
387+
388+
after(() => {
389+
fs.unlinkSync('testCertKey.pem');
390+
fs.unlinkSync('testKey.pem');
391+
fs.unlinkSync('testCert.pem');
392+
});
393+
394+
it('correctly sets the cert and key if only tlsCertificateKeyFile is provided', function () {
395+
const optsFromObject = parseOptions('mongodb://localhost/', {
396+
tlsCertificateKeyFile: 'testCertKey.pem'
397+
});
398+
expect(optsFromObject).to.have.property('cert', 'cert key');
399+
expect(optsFromObject).to.have.property('key', 'cert key');
400+
401+
const optsFromUri = parseOptions('mongodb://localhost?tlsCertificateKeyFile=testCertKey.pem');
402+
expect(optsFromUri).to.have.property('cert', 'cert key');
403+
expect(optsFromUri).to.have.property('key', 'cert key');
404+
});
405+
406+
it('correctly sets the cert and key if both tlsCertificateKeyFile and tlsCertificateFile is provided', function () {
407+
const optsFromObject = parseOptions('mongodb://localhost/', {
408+
tlsCertificateKeyFile: 'testKey.pem',
409+
tlsCertificateFile: 'testCert.pem'
410+
});
411+
expect(optsFromObject).to.have.property('cert', 'test cert');
412+
expect(optsFromObject).to.have.property('key', 'test key');
413+
414+
const optsFromUri = parseOptions(
415+
'mongodb://localhost?tlsCertificateKeyFile=testKey.pem&tlsCertificateFile=testCert.pem'
416+
);
417+
expect(optsFromUri).to.have.property('cert', 'test cert');
418+
expect(optsFromUri).to.have.property('key', 'test key');
419+
});
420+
});
421+
422+
it('throws an error if multiple tls parameters are not all set to the same value', () => {
423+
expect(() => parseOptions('mongodb://localhost?tls=true&tls=false')).to.throw(
424+
'All values of tls/ssl must be the same.'
425+
);
426+
});
427+
428+
it('throws an error if multiple ssl parameters are not all set to the same value', () => {
429+
expect(() => parseOptions('mongodb://localhost?ssl=true&ssl=false')).to.throw(
430+
'All values of tls/ssl must be the same.'
431+
);
432+
});
433+
434+
it('throws an error if tls and ssl parameters are not all set to the same value', () => {
435+
expect(() => parseOptions('mongodb://localhost?tls=true&ssl=false')).to.throw(
436+
'All values of tls/ssl must be the same.'
437+
);
438+
expect(() => parseOptions('mongodb://localhost?tls=false&ssl=true')).to.throw(
439+
'All values of tls/ssl must be the same.'
440+
);
441+
});
442+
443+
it('correctly sets tls if multiple tls parameters are all set to the same value', () => {
444+
expect(parseOptions('mongodb://localhost?tls=true&tls=true')).to.have.property('tls', true);
445+
expect(parseOptions('mongodb://localhost?tls=false&tls=false')).to.have.property('tls', false);
446+
});
447+
448+
it('correctly sets tls if multiple ssl parameters are all set to the same value', () => {
449+
expect(parseOptions('mongodb://localhost?ssl=true&ssl=true')).to.have.property('tls', true);
450+
expect(parseOptions('mongodb://localhost?ssl=false&ssl=false')).to.have.property('tls', false);
451+
});
452+
453+
it('correctly sets tls if tls and ssl parameters are all set to the same value', () => {
454+
expect(parseOptions('mongodb://localhost?ssl=true&tls=true')).to.have.property('tls', true);
455+
expect(parseOptions('mongodb://localhost?ssl=false&tls=false')).to.have.property('tls', false);
456+
});
457+
369458
it('transforms tlsInsecure correctly', function () {
370459
const optionsTrue = parseOptions('mongodb://localhost/', {
371460
tlsInsecure: true

0 commit comments

Comments
 (0)