diff --git a/src/cmap/auth/mongodb_aws.ts b/src/cmap/auth/mongodb_aws.ts index 72859f49676..d9071496b54 100644 --- a/src/cmap/auth/mongodb_aws.ts +++ b/src/cmap/auth/mongodb_aws.ts @@ -148,7 +148,7 @@ export class MongoDBAWS extends AuthProvider { const saslContinue = { saslContinue: 1, - conversationId: 1, + conversationId: saslStartResponse.conversationId, payload: BSON.serialize(payload, bsonOptions) }; diff --git a/test/integration/auth/mongodb_aws.test.ts b/test/integration/auth/mongodb_aws.test.ts index 93778cedf1e..74feeff48fc 100644 --- a/test/integration/auth/mongodb_aws.test.ts +++ b/test/integration/auth/mongodb_aws.test.ts @@ -9,9 +9,14 @@ import * as sinon from 'sinon'; import { refreshKMSCredentials } from '../../../src/client-side-encryption/providers'; import { AWSTemporaryCredentialProvider, + type CommandOptions, + Connection, + type Document, MongoAWSError, type MongoClient, MongoDBAWS, + type MongoDBNamespace, + type MongoDBResponseConstructor, MongoMissingCredentialsError, MongoServerError, setDifference @@ -61,6 +66,76 @@ describe('MONGODB-AWS', function () { expect(result).to.be.a('number'); }); + describe('ConversationId', function () { + let commandStub: sinon.SinonStub< + [ + ns: MongoDBNamespace, + command: Document, + options?: CommandOptions, + responseType?: MongoDBResponseConstructor + ], + Promise + >; + + let saslStartResult, saslContinue; + + beforeEach(function () { + // spy on connection.command, filter for saslStart and saslContinue commands + commandStub = sinon.stub(Connection.prototype, 'command').callsFake(async function ( + ns: MongoDBNamespace, + command: Document, + options: CommandOptions, + responseType?: MongoDBResponseConstructor + ) { + if (command.saslContinue != null) { + saslContinue = { ...command }; + } + + const result = await commandStub.wrappedMethod.call( + this, + ns, + command, + options, + responseType + ); + + if (command.saslStart != null) { + // Modify the result of the saslStart to check if the saslContinue uses it + result.conversationId = 999; + saslStartResult = { ...result }; + } + + return result; + }); + }); + + afterEach(function () { + commandStub.restore(); + sinon.restore(); + }); + + it('should use conversationId returned by saslStart in saslContinue', async function () { + client = this.configuration.newClient(process.env.MONGODB_URI); // use the URI built by the test environment + + const err = await client + .db('aws') + .collection('aws_test') + .estimatedDocumentCount() + .catch(e => e); + + // Expecting the saslContinue to fail since we changed the conversationId + expect(err).to.be.instanceof(MongoServerError); + expect(err.message).to.match(/Mismatched conversation id/); + + expect(saslStartResult).to.not.be.undefined; + expect(saslContinue).to.not.be.undefined; + + expect(saslStartResult).to.have.property('conversationId', 999); + + expect(saslContinue).to.have.property('conversationId').equal(saslStartResult.conversationId); + }); + }); + it('should allow empty string in authMechanismProperties.AWS_SESSION_TOKEN to override AWS_SESSION_TOKEN environment variable', function () { client = this.configuration.newClient(this.configuration.url(), { authMechanismProperties: { AWS_SESSION_TOKEN: '' }