diff --git a/src/cmap/auth/mongodb_oidc.ts b/src/cmap/auth/mongodb_oidc.ts index 1cd249aac21..4cab886112f 100644 --- a/src/cmap/auth/mongodb_oidc.ts +++ b/src/cmap/auth/mongodb_oidc.ts @@ -143,7 +143,7 @@ export class MongoDBOIDC extends AuthProvider { */ override async auth(authContext: AuthContext): Promise { const { connection, reauthenticating, response } = authContext; - if (response?.speculativeAuthenticate?.done) { + if (response?.speculativeAuthenticate?.done && !reauthenticating) { return; } const credentials = getCredentials(authContext); diff --git a/test/integration/auth/mongodb_oidc.prose.test.ts b/test/integration/auth/mongodb_oidc.prose.test.ts index b2acf89e577..477283ba617 100644 --- a/test/integration/auth/mongodb_oidc.prose.test.ts +++ b/test/integration/auth/mongodb_oidc.prose.test.ts @@ -546,6 +546,99 @@ describe('OIDC Auth Spec Tests', function () { expect(callbackSpy).to.have.been.calledTwice; }); }); + + describe('4.4 Speculative Authentication should be ignored on Reauthentication', function () { + let utilClient: MongoClient; + const callbackSpy = sinon.spy(createCallback()); + const saslStarts = []; + // - Create an OIDC configured client. + // - Populate the *Client Cache* with a valid access token to enforce Speculative Authentication. + // - Perform an `insert` operation that succeeds. + // - Assert that the callback was not called. + // - Assert there were no `SaslStart` commands executed. + // - Set a fail point for `insert` commands of the form: + // ```javascript + // { + // configureFailPoint: "failCommand", + // mode: { + // times: 1 + // }, + // data: { + // failCommands: [ + // "insert" + // ], + // errorCode: 391 // ReauthenticationRequired + // } + // } + // ``` + // - Perform an `insert` operation that succeeds. + // - Assert that the callback was called once. + // - Assert there were `SaslStart` commands executed. + // - Close the client. + beforeEach(async function () { + utilClient = new MongoClient(uriSingle, { + authMechanismProperties: { + OIDC_CALLBACK: createCallback() + }, + retryReads: false + }); + + client = new MongoClient(uriSingle, { + authMechanismProperties: { + OIDC_CALLBACK: callbackSpy + }, + retryReads: false, + monitorCommands: true + }); + client.on('commandStarted', event => { + if (event.commandName === 'saslStart') { + saslStarts.push(event); + } + }); + + const provider = client.s.authProviders.getOrCreateProvider('MONGODB-OIDC', { + OIDC_CALLBACK: callbackSpy + }) as MongoDBOIDC; + const token = await readFile(path.join(process.env.OIDC_TOKEN_DIR, 'test_user1'), { + encoding: 'utf8' + }); + + provider.workflow.cache.put({ accessToken: token }); + collection = client.db('test').collection('test'); + }); + + afterEach(async function () { + await utilClient.db().admin().command({ + configureFailPoint: 'failCommand', + mode: 'off' + }); + await utilClient.close(); + }); + + it('successfully authenticates', async function () { + await collection.insertOne({ name: 'test' }); + expect(callbackSpy).to.not.have.been.called; + expect(saslStarts).to.be.empty; + + await utilClient + .db() + .admin() + .command({ + configureFailPoint: 'failCommand', + mode: { + times: 1 + }, + data: { + failCommands: ['insert'], + errorCode: 391 + } + }); + + await collection.insertOne({ name: 'test' }); + expect(callbackSpy).to.have.been.calledOnce; + expect(saslStarts.length).to.equal(1); + }); + }); }); });