Skip to content

Commit 0ea6eaa

Browse files
authored
feat(NODE-4179): allow secureContext in KMS TLS options (#4578)
1 parent d92acfc commit 0ea6eaa

File tree

3 files changed

+252
-57
lines changed

3 files changed

+252
-57
lines changed

src/client-side-encryption/state_machine.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ declare module 'mongodb-client-encryption' {
106106
*/
107107
export type ClientEncryptionTlsOptions = Pick<
108108
MongoClientOptions,
109-
'tlsCAFile' | 'tlsCertificateKeyFile' | 'tlsCertificateKeyFilePassword'
109+
'tlsCAFile' | 'tlsCertificateKeyFile' | 'tlsCertificateKeyFilePassword' | 'secureContext'
110110
>;
111111

112112
/** @public */
@@ -521,6 +521,10 @@ export class StateMachine {
521521
tlsOptions: ClientEncryptionTlsOptions,
522522
options: tls.ConnectionOptions
523523
): Promise<void> {
524+
// If a secureContext is provided, ensure it is set.
525+
if (tlsOptions.secureContext) {
526+
options.secureContext = tlsOptions.secureContext;
527+
}
524528
if (tlsOptions.tlsCertificateKeyFile) {
525529
const cert = await fs.readFile(tlsOptions.tlsCertificateKeyFile);
526530
options.cert = options.key = cert;

test/integration/client-side-encryption/client_side_encryption.prose.test.js renamed to test/integration/client-side-encryption/client_side_encryption.prose.test.ts

Lines changed: 68 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,24 @@
1-
'use strict';
2-
const BSON = require('bson');
3-
const { expect } = require('chai');
4-
const fs = require('fs');
5-
const path = require('path');
6-
7-
const { dropCollection, APMEventCollector } = require('../shared');
8-
9-
const { EJSON } = BSON;
10-
const { LEGACY_HELLO_COMMAND, MongoCryptError, MongoRuntimeError } = require('../../mongodb');
11-
const { MongoServerError, MongoServerSelectionError, MongoClient } = require('../../mongodb');
12-
const { getEncryptExtraOptions } = require('../../tools/utils');
13-
14-
const {
15-
externalSchema
16-
} = require('../../spec/client-side-encryption/external/external-schema.json');
17-
/* eslint-disable no-restricted-modules */
18-
const { ClientEncryption } = require('../../../src/client-side-encryption/client_encryption');
19-
const { getCSFLEKMSProviders } = require('../../csfle-kms-providers');
20-
const { AlpineTestConfiguration } = require('../../tools/runner/config');
21-
22-
const getKmsProviders = (localKey, kmipEndpoint, azureEndpoint, gcpEndpoint) => {
1+
import { BSON, EJSON } from 'bson';
2+
import { expect } from 'chai';
3+
import * as fs from 'fs/promises';
4+
import * as path from 'path';
5+
6+
// eslint-disable-next-line @typescript-eslint/no-restricted-imports
7+
import { ClientEncryption } from '../../../src/client-side-encryption/client_encryption';
8+
import { getCSFLEKMSProviders } from '../../csfle-kms-providers';
9+
import {
10+
LEGACY_HELLO_COMMAND,
11+
MongoClient,
12+
MongoCryptError,
13+
MongoRuntimeError,
14+
MongoServerError,
15+
MongoServerSelectionError
16+
} from '../../mongodb';
17+
import { AlpineTestConfiguration } from '../../tools/runner/config';
18+
import { getEncryptExtraOptions } from '../../tools/utils';
19+
import { APMEventCollector, dropCollection } from '../shared';
20+
21+
export const getKmsProviders = (localKey, kmipEndpoint, azureEndpoint, gcpEndpoint) => {
2322
const result = getCSFLEKMSProviders();
2423
if (localKey) {
2524
result.local = { key: localKey };
@@ -39,23 +38,41 @@ const getKmsProviders = (localKey, kmipEndpoint, azureEndpoint, gcpEndpoint) =>
3938
return result;
4039
};
4140

41+
// eslint-disable-next-line @typescript-eslint/no-empty-function
4242
const noop = () => {};
43-
/** @type { MongoDBMetadataUI } */
44-
const metadata = {
43+
const metadata: MongoDBMetadataUI = {
4544
requires: {
4645
clientSideEncryption: true,
4746
topology: '!load-balanced'
4847
}
4948
};
5049

51-
const eeMetadata = {
50+
const eeMetadata: MongoDBMetadataUI = {
5251
requires: {
5352
clientSideEncryption: true,
5453
mongodb: '>=7.0.0',
5554
topology: ['replicaset', 'sharded']
5655
}
5756
};
5857

58+
async function loadExternal(file) {
59+
return EJSON.parse(
60+
await fs.readFile(
61+
path.resolve(__dirname, '../../spec/client-side-encryption/external', file),
62+
'utf8'
63+
)
64+
);
65+
}
66+
67+
async function loadLimits(file) {
68+
return EJSON.parse(
69+
await fs.readFile(
70+
path.resolve(__dirname, '../../spec/client-side-encryption/limits', file),
71+
'utf8'
72+
)
73+
);
74+
}
75+
5976
// Tests for the ClientEncryption type are not included as part of the YAML tests.
6077

6178
// In the prose tests LOCAL_MASTERKEY refers to the following base64:
@@ -64,6 +81,9 @@ const eeMetadata = {
6481

6582
// Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk
6683
describe('Client Side Encryption Prose Tests', metadata, function () {
84+
let externalKey;
85+
let externalSchema;
86+
6787
const dataDbName = 'db';
6888
const dataCollName = 'coll';
6989
const dataNamespace = `${dataDbName}.${dataCollName}`;
@@ -76,6 +96,11 @@ describe('Client Side Encryption Prose Tests', metadata, function () {
7696
'base64'
7797
);
7898

99+
before(async function () {
100+
externalKey = await loadExternal('external-key.json');
101+
externalSchema = await loadExternal('external-schema.json');
102+
});
103+
79104
describe('Data key and double encryption', function () {
80105
// Data key and double encryption
81106
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -351,18 +376,8 @@ describe('Client Side Encryption Prose Tests', metadata, function () {
351376
// and confirming that the externalClient is firing off keyVault requests during
352377
// encrypted operations
353378
describe('External Key Vault Test', function () {
354-
function loadExternal(file) {
355-
return EJSON.parse(
356-
fs.readFileSync(path.resolve(__dirname, '../../spec/client-side-encryption/external', file))
357-
);
358-
}
359-
360-
const externalKey = loadExternal('external-key.json');
361-
const externalSchema = loadExternal('external-schema.json');
362-
363-
beforeEach(function () {
379+
beforeEach(async function () {
364380
this.client = this.configuration.newClient();
365-
366381
// 1. Create a MongoClient without encryption enabled (referred to as ``client``).
367382
return (
368383
this.client
@@ -552,15 +567,15 @@ describe('Client Side Encryption Prose Tests', metadata, function () {
552567
});
553568

554569
describe('BSON size limits and batch splitting', function () {
555-
function loadLimits(file) {
556-
return EJSON.parse(
557-
fs.readFileSync(path.resolve(__dirname, '../../spec/client-side-encryption/limits', file))
558-
);
559-
}
560-
561-
const limitsSchema = loadLimits('limits-schema.json');
562-
const limitsKey = loadLimits('limits-key.json');
563-
const limitsDoc = loadLimits('limits-doc.json');
570+
let limitsSchema;
571+
let limitsKey;
572+
let limitsDoc;
573+
574+
before(async function () {
575+
limitsSchema = await loadLimits('limits-schema.json');
576+
limitsKey = await loadLimits('limits-key.json');
577+
limitsDoc = await loadLimits('limits-doc.json');
578+
});
564579

565580
let hasRunFirstTimeSetup = false;
566581

@@ -827,9 +842,9 @@ describe('Client Side Encryption Prose Tests', metadata, function () {
827842

828843
describe('Corpus Test', function () {
829844
it('runs in a separate suite', () => {
830-
expect(() =>
831-
fs.statSync(path.resolve(__dirname, './client_side_encryption.prose.06.corpus.test.ts'))
832-
).not.to.throw();
845+
expect(async () => {
846+
await fs.stat(path.resolve(__dirname, './client_side_encryption.prose.06.corpus.test.ts'));
847+
}).not.to.throw();
833848
});
834849
});
835850

@@ -1687,6 +1702,7 @@ describe('Client Side Encryption Prose Tests', metadata, function () {
16871702
context(
16881703
'Case 5: `tlsDisableOCSPEndpointCheck` is permitted',
16891704
metadata,
1705+
// eslint-disable-next-line @typescript-eslint/no-empty-function
16901706
function () {}
16911707
).skipReason = 'TODO(NODE-4840): Node does not support any OCSP options';
16921708

@@ -1907,12 +1923,12 @@ describe('Client Side Encryption Prose Tests', metadata, function () {
19071923
beforeEach(async function () {
19081924
// Load the file encryptedFields.json as encryptedFields.
19091925
encryptedFields = EJSON.parse(
1910-
await fs.promises.readFile(path.join(data, 'encryptedFields.json')),
1926+
await fs.readFile(path.join(data, 'encryptedFields.json'), 'utf8'),
19111927
{ relaxed: false }
19121928
);
19131929
// Load the file key1-document.json as key1Document.
19141930
key1Document = EJSON.parse(
1915-
await fs.promises.readFile(path.join(data, 'keys', 'key1-document.json')),
1931+
await fs.readFile(path.join(data, 'keys', 'key1-document.json'), 'utf8'),
19161932
{ relaxed: false }
19171933
);
19181934
// Read the "_id" field of key1Document as key1ID.
@@ -2308,15 +2324,13 @@ describe('Client Side Encryption Prose Tests', metadata, function () {
23082324
kmip: {},
23092325
local: undefined
23102326
};
2311-
/** @type {import('../../mongodb').MongoClient} */
23122327
let client1;
2313-
/** @type {import('../../mongodb').MongoClient} */
23142328
let client2;
23152329

23162330
describe('Case 1: Rewrap with separate ClientEncryption', function () {
23172331
/**
2318-
* Run the following test case for each pair of KMS providers (referred to as ``srcProvider`` and ``dstProvider``).
2319-
* Include pairs where ``srcProvider`` equals ``dstProvider``.
2332+
* Run the following test case for each pair of KMS providers (referred to as `srcProvider` and `dstProvider`).
2333+
* Include pairs where `srcProvider` equals `dstProvider`.
23202334
*/
23212335
function* generateTestCombinations() {
23222336
const providers = Object.keys(masterKeys);

0 commit comments

Comments
 (0)