From a6882ec1a3c3958f56d377e7bbf5bac343dcc235 Mon Sep 17 00:00:00 2001 From: Bailey Pearson Date: Thu, 18 Apr 2024 11:49:06 -0600 Subject: [PATCH] test(NODE-5443): x509 auth (#4080) --- .evergreen/config.in.yml | 12 + .evergreen/config.yml | 33 + .evergreen/generate_evergreen_tasks.js | 16 + .evergreen/run-x509-tests.sh | 22 + package.json | 1 + .../integration/auth/ssl_x509_connect.test.js | 599 ------------------ test/manual/x509_auth.test.ts | 134 ++++ 7 files changed, 218 insertions(+), 599 deletions(-) create mode 100644 .evergreen/run-x509-tests.sh delete mode 100644 test/integration/auth/ssl_x509_connect.test.js create mode 100644 test/manual/x509_auth.test.ts diff --git a/.evergreen/config.in.yml b/.evergreen/config.in.yml index 8961baa6f9..6c0fecc05b 100644 --- a/.evergreen/config.in.yml +++ b/.evergreen/config.in.yml @@ -1111,6 +1111,18 @@ functions: binary: bash args: - ${PROJECT_DIRECTORY}/.evergreen/run-benchmarks.sh + "run x509 auth tests": + - command: subprocess.exec + type: test + params: + working_dir: "src" + env: + PROJECT_DIRECTORY: ${PROJECT_DIRECTORY} + MONGODB_URI: ${MONGODB_URI} + DRIVERS_TOOLS: ${DRIVERS_TOOLS} + binary: bash + args: + - ${PROJECT_DIRECTORY}/.evergreen/run-x509-tests.sh tasks: - name: 'test-atlas-data-lake' diff --git a/.evergreen/config.yml b/.evergreen/config.yml index 0db1fbe007..8d5a9dadbc 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -1071,6 +1071,18 @@ functions: binary: bash args: - ${PROJECT_DIRECTORY}/.evergreen/run-benchmarks.sh + run x509 auth tests: + - command: subprocess.exec + type: test + params: + working_dir: src + env: + PROJECT_DIRECTORY: ${PROJECT_DIRECTORY} + MONGODB_URI: ${MONGODB_URI} + DRIVERS_TOOLS: ${DRIVERS_TOOLS} + binary: bash + args: + - ${PROJECT_DIRECTORY}/.evergreen/run-x509-tests.sh tasks: - name: test-atlas-data-lake tags: @@ -1731,6 +1743,23 @@ tasks: - func: bootstrap mongo-orchestration - func: bootstrap kms servers - func: run tests + - name: test-x509-authentication + tags: + - latest + - auth + - x509 + commands: + - command: expansions.update + type: setup + params: + updates: + - {key: VERSION, value: latest} + - {key: TOPOLOGY, value: sharded_cluster} + - {key: AUTH, value: noauth} + - {key: SSL, value: ssl} + - func: install dependencies + - func: bootstrap mongo-orchestration + - func: run x509 auth tests - name: test-atlas-connectivity tags: - atlas-connect @@ -3975,6 +4004,7 @@ buildvariants: - test-3.6-replica_set - test-3.6-sharded_cluster - test-latest-server-v1-api + - test-x509-authentication - test-atlas-connectivity - test-5.0-load-balanced - test-6.0-load-balanced @@ -4028,6 +4058,7 @@ buildvariants: - test-3.6-replica_set - test-3.6-sharded_cluster - test-latest-server-v1-api + - test-x509-authentication - test-atlas-connectivity - test-5.0-load-balanced - test-6.0-load-balanced @@ -4081,6 +4112,7 @@ buildvariants: - test-3.6-replica_set - test-3.6-sharded_cluster - test-latest-server-v1-api + - test-x509-authentication - test-atlas-connectivity - test-5.0-load-balanced - test-6.0-load-balanced @@ -4133,6 +4165,7 @@ buildvariants: - test-3.6-replica_set - test-3.6-sharded_cluster - test-latest-server-v1-api + - test-x509-authentication - test-atlas-connectivity - test-5.0-load-balanced - test-6.0-load-balanced diff --git a/.evergreen/generate_evergreen_tasks.js b/.evergreen/generate_evergreen_tasks.js index c45273234f..406b926cab 100644 --- a/.evergreen/generate_evergreen_tasks.js +++ b/.evergreen/generate_evergreen_tasks.js @@ -114,6 +114,22 @@ BASE_TASKS.push({ ] }); +BASE_TASKS.push({ + name: `test-x509-authentication`, + tags: ['latest', 'auth', 'x509'], + commands: [ + updateExpansions({ + VERSION: 'latest', + TOPOLOGY: 'sharded_cluster', + AUTH: 'noauth', + SSL: 'ssl' + }), + { func: 'install dependencies' }, + { func: 'bootstrap mongo-orchestration' }, + { func: 'run x509 auth tests' } + ] +}) + // manually added tasks TASKS.push( ...[ diff --git a/.evergreen/run-x509-tests.sh b/.evergreen/run-x509-tests.sh new file mode 100644 index 0000000000..0e65800cb1 --- /dev/null +++ b/.evergreen/run-x509-tests.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +source "${PROJECT_DIRECTORY}/.evergreen/init-node-and-npm-env.sh" + +set -o errexit + +export SSL_KEY_FILE=$DRIVERS_TOOLS/.evergreen/x509gen/client.pem +export SSL_CA_FILE=$DRIVERS_TOOLS/.evergreen/x509gen/ca.pem +export SSL_KEY_FILE_EXPIRED=$DRIVERS_TOOLS/.evergreen/x509gen/expired.pem +export SSL_KEY_NO_USER=$DRIVERS_TOOLS/.evergreen/x509gen/crl.pem + +SUBJECT=$(openssl x509 -subject -nameopt RFC2253 -noout -inform PEM -in $SSL_KEY_FILE) + +# Strip `subject=` prefix from the subject +SUBJECT=${SUBJECT#"subject="} + +# Remove any leading or trailing whitespace +SUBJECT=$(echo "$SUBJECT" | awk '{$1=$1;print}') + +export SUBJECT + +npm run check:x509 diff --git a/package.json b/package.json index ffb24187c3..c2ca73e00f 100644 --- a/package.json +++ b/package.json @@ -158,6 +158,7 @@ "check:socks5": "mocha --config test/manual/mocharc.json test/manual/socks5.test.ts", "check:csfle": "mocha --config test/mocha_mongodb.json test/integration/client-side-encryption", "check:snappy": "mocha test/unit/assorted/snappy.test.js", + "check:x509": "mocha test/manual/x509_auth.test.ts", "fix:eslint": "npm run check:eslint -- --fix", "prepare": "node etc/prepare.js", "preview:docs": "ts-node etc/docs/preview.ts", diff --git a/test/integration/auth/ssl_x509_connect.test.js b/test/integration/auth/ssl_x509_connect.test.js deleted file mode 100644 index 307b682747..0000000000 --- a/test/integration/auth/ssl_x509_connect.test.js +++ /dev/null @@ -1,599 +0,0 @@ -'use strict'; -const fs = require('fs'); -const { format: f } = require('util'); -const { test, setupDatabase } = require('../shared'); -const { expect } = require('chai'); -const { MongoClient } = require('../../mongodb'); - -describe('SSL (x509)', function () { - before(function () { - return setupDatabase(this.configuration); - }); - - it('Should correctly authenticate using x509', { - metadata: { requires: { topology: 'ssl' } }, - - test: function (done) { - var configuration = this.configuration; - var ServerManager = require('mongodb-topology-manager').Server; - - // Read the cert and key - var cert = fs.readFileSync(__dirname + '/ssl/x509/client.pem'); - var key = fs.readFileSync(__dirname + '/ssl/x509/client.pem'); - - // User name - var userName = 'CN=client,OU=kerneluser,O=10Gen,L=New York City,ST=New York,C=US'; - - // Create server manager - var serverManager = new ServerManager( - 'mongod', - { - bind_ip: 'server', - port: 27019, - dbpath: f('%s/../db/27019', __dirname), - sslPEMKeyFile: __dirname + '/ssl/x509/server.pem', - sslCAFile: __dirname + '/ssl/x509/ca.pem', - sslCRLFile: __dirname + '/ssl/x509/crl.pem', - sslMode: 'requireSSL', - sslWeakCertificateValidation: null - }, - { - ssl: true, - host: 'server', - key: cert, - cert: cert, - rejectUnauthorized: false - } - ); - - // Purge the set - serverManager.purge().then(function () { - // Start the server - serverManager.start().then(function () { - // Connect and validate the server certificate - MongoClient.connect( - 'mongodb://server:27019/test?ssl=true&maxPoolSize=1', - { - server: { - sslKey: key, - sslCert: cert, - sslValidate: false - } - }, - function (err, client) { - expect(err).to.not.exist; - var db = client.db(configuration.db); - - // Execute build info - db.command({ buildInfo: 1 }, function (err, result) { - expect(err).to.not.exist; - var version = parseInt(result.versionArray.slice(0, 3).join(''), 10); - if (version < 253) { - client.close(); - return done(); - } - - // Add the X509 auth user to the $external db - var ext = client.db('$external'); - ext.addUser( - userName, - { - roles: [ - { role: 'readWriteAnyDatabase', db: 'admin' }, - { role: 'userAdminAnyDatabase', db: 'admin' } - ] - }, - function (err, result) { - expect(err).to.not.exist; - test.equal(userName, result[0].user); - test.equal('', result[0].pwd); - client.close(); - - // Connect using X509 authentication - MongoClient.connect( - f( - 'mongodb://%s@server:27019/test?authMechanism=%s&ssl=true&maxPoolSize=1', - encodeURIComponent(userName), - 'MONGODB-X509' - ), - { - server: { - sslKey: key, - sslCert: cert, - sslValidate: false - } - }, - function (err, client) { - expect(err).to.not.exist; - - client.close(); - - serverManager.stop().then(function () { - done(); - }); - } - ); - } - ); - }); - } - ); - }); - }); - } - }); - - it('Should correctly handle bad x509 certificate', { - metadata: { requires: { topology: 'ssl' } }, - - test: function (done) { - var configuration = this.configuration; - var ServerManager = require('mongodb-topology-manager').Server; - - // Read the cert and key - var cert = fs.readFileSync(__dirname + '/ssl/x509/client.pem'); - var key = fs.readFileSync(__dirname + '/ssl/x509/client.pem'); - var serverPem = fs.readFileSync(__dirname + '/ssl/x509/server.pem'); - - // User name - var userName = 'CN=client,OU=kerneluser,O=10Gen,L=New York City,ST=New York,C=US'; - - // Create server manager - var serverManager = new ServerManager( - 'mongod', - { - bind_ip: 'server', - port: 27019, - dbpath: f('%s/../db/27019', __dirname), - sslPEMKeyFile: __dirname + '/ssl/x509/server.pem', - sslCAFile: __dirname + '/ssl/x509/ca.pem', - sslCRLFile: __dirname + '/ssl/x509/crl.pem', - sslMode: 'requireSSL', - sslWeakCertificateValidation: null - }, - { - ssl: true, - host: 'server', - key: cert, - cert: cert, - rejectUnauthorized: false - } - ); - - // Purge the set - serverManager.purge().then(function () { - // Start the server - serverManager.start().then(function () { - // Connect and validate the server certificate - MongoClient.connect( - 'mongodb://server:27019/test?ssl=true&maxPoolSize=1', - { - server: { - sslKey: key, - sslCert: cert, - sslValidate: false - } - }, - function (err, client) { - expect(err).to.not.exist; - var db = client.db(configuration.db); - - // Execute build info - db.command({ buildInfo: 1 }, function (err, result) { - expect(err).to.not.exist; - var version = parseInt(result.versionArray.slice(0, 3).join(''), 10); - if (version < 253) { - client.close(); - return done(); - } - - // Add the X509 auth user to the $external db - var ext = client.db('$external'); - ext.addUser( - userName, - { - roles: [ - { role: 'readWriteAnyDatabase', db: 'admin' }, - { role: 'userAdminAnyDatabase', db: 'admin' } - ] - }, - function (err, result) { - expect(err).to.not.exist; - test.equal(userName, result[0].user); - test.equal('', result[0].pwd); - client.close(); - - // Connect using X509 authentication - MongoClient.connect( - f( - 'mongodb://%s@server:27019/test?authMechanism=%s&ssl=true&maxPoolSize=1', - encodeURIComponent(userName), - 'MONGODB-X509' - ), - { - server: { - sslKey: serverPem, - sslCert: serverPem, - sslValidate: false - } - }, - function (err) { - test.equal(0, err.ok); - test.equal('auth failed', err.errmsg); - - serverManager.stop().then(function () { - done(); - }); - } - ); - } - ); - }); - } - ); - }); - }); - } - }); - - it('Should give reasonable error on x509 authentication failure', { - metadata: { requires: { topology: 'ssl' } }, - - test: function (done) { - var configuration = this.configuration; - var ServerManager = require('mongodb-topology-manager').Server; - - // Read the cert and key - var cert = fs.readFileSync(__dirname + '/ssl/x509/client.pem'); - var key = fs.readFileSync(__dirname + '/ssl/x509/client.pem'); - - // User name - var userName = 'CN=client,OU=kerneluser,O=10Gen,L=New York City,ST=New York,C=US'; - - // Create server manager - var serverManager = new ServerManager( - 'mongod', - { - bind_ip: 'server', - port: 27019, - dbpath: f('%s/../db/27019', __dirname), - sslPEMKeyFile: __dirname + '/ssl/x509/server.pem', - sslCAFile: __dirname + '/ssl/x509/ca.pem', - sslCRLFile: __dirname + '/ssl/x509/crl.pem', - sslMode: 'requireSSL', - sslWeakCertificateValidation: null - }, - { - ssl: true, - host: 'server', - key: cert, - cert: cert, - rejectUnauthorized: false - } - ); - - // Purge the set - serverManager.purge().then(function () { - // Start the server - serverManager.start().then(function () { - // Connect and validate the server certificate - MongoClient.connect( - 'mongodb://server:27019/test?ssl=true&maxPoolSize=1', - { - server: { - sslKey: key, - sslCert: cert, - sslValidate: false - } - }, - function (err, client) { - expect(err).to.not.exist; - var db = client.db(configuration.db); - - // Execute build info - db.command({ buildInfo: 1 }, function (err, result) { - expect(err).to.not.exist; - var version = parseInt(result.versionArray.slice(0, 3).join(''), 10); - if (version < 253) { - client.close(); - return done(); - } - - // Add the X509 auth user to the $external db - var ext = client.db('$external'); - ext.addUser( - userName, - { - roles: [ - { role: 'readWriteAnyDatabase', db: 'admin' }, - { role: 'userAdminAnyDatabase', db: 'admin' } - ] - }, - function (err, result) { - expect(err).to.not.exist; - test.equal(userName, result[0].user); - test.equal('', result[0].pwd); - client.close(); - - // Connect using X509 authentication - MongoClient.connect( - f( - 'mongodb://%s@server:27019/test?authMechanism=%s&ssl=true&maxPoolSize=1', - encodeURIComponent('WRONG_USERNAME'), - 'MONGODB-X509' - ), - { - server: { - sslKey: key, - sslCert: cert, - sslValidate: false - } - }, - function (err) { - test.equal(0, err.ok); - test.equal('auth failed', err.errmsg); - - serverManager.stop().then(function () { - done(); - }); - } - ); - } - ); - }); - } - ); - }); - }); - } - }); - - it('Should give helpful error when attempting to use x509 without SSL', { - metadata: { requires: { topology: 'ssl' } }, - - test: function (done) { - var configuration = this.configuration; - var ServerManager = require('mongodb-topology-manager').Server; - - // Read the cert and key - var cert = fs.readFileSync(__dirname + '/ssl/x509/client.pem'); - var key = fs.readFileSync(__dirname + '/ssl/x509/client.pem'); - var serverPem = fs.readFileSync(__dirname + '/ssl/x509/server.pem'); - - // User name - var userName = 'CN=client,OU=kerneluser,O=10Gen,L=New York City,ST=New York,C=US'; - - // Create server manager - var serverManager = new ServerManager( - 'mongod', - { - bind_ip: 'server', - port: 27019, - dbpath: f('%s/../db/27019', __dirname) - }, - {} - ); - - // Purge the set - serverManager.purge().then(function () { - // Start the server - serverManager.start().then(function () { - // Connect and validate the server certificate - MongoClient.connect( - 'mongodb://server:27019/test?ssl=false&maxPoolSize=1', - { - server: { - sslKey: key, - sslCert: cert, - sslValidate: false - } - }, - function (err, client) { - expect(err).to.not.exist; - var db = client.db(configuration.db); - - // Execute build info - db.command({ buildInfo: 1 }, function (err, result) { - expect(err).to.not.exist; - var version = parseInt(result.versionArray.slice(0, 3).join(''), 10); - if (version < 253) { - client.close(); - return done(); - } - - // Add the X509 auth user to the $external db - var ext = client.db('$external'); - ext.addUser( - userName, - { - roles: [ - { role: 'readWriteAnyDatabase', db: 'admin' }, - { role: 'userAdminAnyDatabase', db: 'admin' } - ] - }, - function (err, result) { - expect(err).to.not.exist; - test.equal(userName, result[0].user); - test.equal('', result[0].pwd); - client.close(); - - // Connect using X509 authentication - MongoClient.connect( - f( - 'mongodb://%s@server:27019/test?authMechanism=%s&ssl=false&maxPoolSize=1', - encodeURIComponent(userName), - 'MONGODB-X509' - ), - { - server: { - sslKey: serverPem, - sslCert: serverPem, - sslValidate: false - } - }, - function (err) { - test.ok(!!err); - test.equal(0, err.ok); - test.equal( - 'SSL support is required for the MONGODB-X509 mechanism.', - err.errmsg - ); - - serverManager.stop().then(function () { - done(); - }); - } - ); - } - ); - }); - } - ); - }); - }); - } - }); - - it('Should correctly reauthenticate against x509', { - metadata: { requires: { topology: 'ssl' } }, - - test: function (done) { - var configuration = this.configuration; - var ServerManager = require('mongodb-topology-manager').Server; - - // Read the cert and key - var cert = fs.readFileSync(__dirname + '/ssl/x509/client.pem'); - var key = fs.readFileSync(__dirname + '/ssl/x509/client.pem'); - - // User name - var userName = 'CN=client,OU=kerneluser,O=10Gen,L=New York City,ST=New York,C=US'; - - // Create server manager - var serverManager = new ServerManager( - 'mongod', - { - bind_ip: 'server', - port: 27019, - dbpath: f('%s/../db/27019', __dirname), - sslPEMKeyFile: __dirname + '/ssl/x509/server.pem', - sslCAFile: __dirname + '/ssl/x509/ca.pem', - sslCRLFile: __dirname + '/ssl/x509/crl.pem', - sslMode: 'requireSSL', - sslWeakCertificateValidation: null - }, - { - ssl: true, - host: 'server', - key: cert, - cert: cert, - rejectUnauthorized: false - } - ); - - // Purge the set - serverManager.purge().then(function () { - // Start the server - serverManager.start().then(function () { - // Connect and validate the server certificate - MongoClient.connect( - 'mongodb://server:27019/test?ssl=true&maxPoolSize=1', - { - server: { - sslKey: key, - sslCert: cert, - sslValidate: false - } - }, - function (err, client) { - expect(err).to.not.exist; - var db = client.db(configuration.db); - - // Execute build info - db.command({ buildInfo: 1 }, function (err, result) { - expect(err).to.not.exist; - var version = parseInt(result.versionArray.slice(0, 3).join(''), 10); - if (version < 253) { - client.close(); - return done(); - } - - // Add the X509 auth user to the $external db - var ext = client.db('$external'); - ext.addUser( - userName, - { - roles: [ - { role: 'readWriteAnyDatabase', db: 'admin' }, - { role: 'userAdminAnyDatabase', db: 'admin' } - ] - }, - function (err, result) { - expect(err).to.not.exist; - test.equal(userName, result[0].user); - test.equal('', result[0].pwd); - client.close(); - - // Connect using X509 authentication - MongoClient.connect( - f( - 'mongodb://%s@server:27019/test?authMechanism=%s&ssl=true&maxPoolSize=1', - encodeURIComponent(userName), - 'MONGODB-X509' - ), - { - server: { - sslKey: key, - sslCert: cert, - sslValidate: false - } - }, - function (err, client) { - expect(err).to.not.exist; - var db = client.db(configuration.db); - - db.collection('x509collection').insert({ a: 1 }, function (err) { - expect(err).to.not.exist; - - db.collection('x509collection').findOne(function (err, doc) { - expect(err).to.not.exist; - test.equal(1, doc.a); - - client.topology.once('reconnect', function () { - // Await reconnect and re-authentication - db.collection('x509collection').findOne(function (err, doc) { - expect(err).to.not.exist; - test.equal(1, doc.a); - - // Attempt disconnect again - client.topology.connections()[0].destroy(); - - // Await reconnect and re-authentication - db.collection('x509collection').findOne(function (err, doc) { - expect(err).to.not.exist; - test.equal(1, doc.a); - - client.close(); - - serverManager.stop().then(function () { - done(); - }); - }); - }); - }); - - // Force close - client.topology.connections()[0].destroy(); - }); - }); - } - ); - } - ); - }); - } - ); - }); - }); - } - }); -}); diff --git a/test/manual/x509_auth.test.ts b/test/manual/x509_auth.test.ts new file mode 100644 index 0000000000..0af6e236a6 --- /dev/null +++ b/test/manual/x509_auth.test.ts @@ -0,0 +1,134 @@ +import { expect } from 'chai'; +import { ConnectionString } from 'mongodb-connection-string-url'; + +import { + MongoClient, + type MongoClientOptions, + MongoServerError, + MongoServerSelectionError +} from '../../src'; + +// eslint-disable-next-line @typescript-eslint/no-non-null-assertion +const connectionString = new ConnectionString(process.env.MONGODB_URI!); + +describe('x509 Authentication', function () { + let client: MongoClient; + const validOptions: MongoClientOptions = { + tls: true, + tlsCertificateKeyFile: process.env.SSL_KEY_FILE, + tlsCAFile: process.env.SSL_CA_FILE, + authMechanism: 'MONGODB-X509' as const, + authSource: '$external' + }; + + this.afterEach(() => { + return client?.close(); + }); + + context('When the user provides a valid certificate', function () { + before('create x509 user', createX509User); + after('drop x509 user', dropX509User); + + it('successfully authenticates using x509', async function () { + client = new MongoClient(connectionString.toString(), validOptions); + const result = await client + .db('aws') + .collection('x509_test') + .estimatedDocumentCount() + .catch(error => error); + + expect(result).to.not.be.instanceOf(MongoServerError); + expect(result).to.be.a('number'); + }); + + context('when an incorrect username is supplied', function () { + it('fails to authenticate', async function () { + const uri = connectionString.clone(); + uri.username = 'bob'; + client = new MongoClient(uri.toString(), validOptions); + const error = await client.connect().catch(error => error); + + expect(error).to.be.instanceOf(MongoServerError); + expect(error.codeName).to.match(/AuthenticationFailed/i); + }); + }); + }); + + context( + 'when a valid cert is provided but the certificate does not correspond to a user', + function () { + it('fails to authenticate', async function () { + client = new MongoClient(connectionString.toString(), validOptions); + const error = await client.connect().catch(e => e); + + expect(error).to.be.instanceOf(MongoServerError); + expect(error.codeName).to.match(/UserNotFound/i); + }); + } + ); + + context('when the client connects with an invalid certificate', function () { + // unlike other authentication mechanisms, x509 authentication 1) requires TLS and + // 2) the server uses the client certificate to derive a username to authenticate with + // against the $external database. This means that if a user attempts to connect to a + // cluster with an invalid certificate and tls is enabled, then the driver fails to connect and + // a server selection error is thrown. + it('throws a server selection error', async function () { + const invalidOptions: MongoClientOptions = { + // use an expired key file + tlsCertificateKeyFile: process.env.SSL_KEY_FILE_EXPIRED, + tlsCAFile: process.env.SSL_CA_FILE, + authMechanism: 'MONGODB-X509' as const, + authSource: '$external' + }; + client = new MongoClient(connectionString.toString(), { + ...invalidOptions, + serverSelectionTimeoutMS: 5000 + }); + const error = await client.connect().catch(e => e); + + expect(error).to.be.instanceOf(MongoServerSelectionError); + }); + }); +}); + +async function createX509User() { + const utilClient = new MongoClient(connectionString.toString(), { + tls: true, + tlsCertificateKeyFile: process.env.SSL_KEY_FILE, + tlsCAFile: process.env.SSL_CA_FILE, + serverSelectionTimeoutMS: 2000 + }); + + try { + await utilClient.connect(); + await utilClient.db('$external').command({ + createUser: process.env.SUBJECT, + roles: [ + { role: 'readWrite', db: 'test' }, + { role: 'userAdminAnyDatabase', db: 'admin' } + ], + writeConcern: { w: 'majority', wtimeout: 5000 } + }); + } finally { + await utilClient.close(); + } +} + +async function dropX509User() { + const utilClient = new MongoClient(connectionString.toString(), { + tls: true, + tlsCertificateKeyFile: process.env.SSL_KEY_FILE, + tlsCAFile: process.env.SSL_CA_FILE, + serverSelectionTimeoutMS: 2000 + }); + try { + await utilClient.connect(); + await utilClient.db('$external').command({ + dropUser: process.env.SUBJECT, + writeConcern: { w: 'majority', wtimeout: 5000 } + }); + } finally { + await utilClient.close(); + } +}