Skip to content
This repository has been archived by the owner on Feb 4, 2022. It is now read-only.

Commit

Permalink
fix(auth): prevent stalling on authentication when connected
Browse files Browse the repository at this point in the history
ReplicaSet was storing the authentication call in the disconnectHandler
when it didn't need to, leading to auth stalling. From now on, will
only store handlers if ReplSet is not actually connected.

NODE-1402
  • Loading branch information
mbroadst committed Apr 17, 2018
1 parent e230d54 commit 6b4ac89
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 1 deletion.
2 changes: 1 addition & 1 deletion lib/topologies/replset.js
Expand Up @@ -1413,7 +1413,7 @@ ReplSet.prototype.auth = function(mechanism, db) {

// Topology is not connected, save the call in the provided store to be
// Executed at some point when the handler deems it's reconnected
if (self.s.disconnectHandler != null) {
if (!this.isConnected() && self.s.disconnectHandler != null) {
if (!self.s.replicaSetState.hasPrimary() && !self.s.options.secondaryOnlyConnectionAllowed) {
return self.s.disconnectHandler.add('auth', db, allArgs, {}, callback);
} else if (
Expand Down
67 changes: 67 additions & 0 deletions test/tests/unit/replset/auth_tests.js
@@ -0,0 +1,67 @@
'use strict';

const ReplSet = require('../../../../lib/topologies/replset');
const mock = require('mongodb-mock-server');
const ReplSetFixture = require('../common').ReplSetFixture;
const ReadPreference = require('../../../../lib/topologies/read_preference');

describe('Auth (ReplSet)', function() {
let test;
before(() => (test = new ReplSetFixture()));
afterEach(() => mock.cleanup());
beforeEach(() => test.setup());

// mock ops store from node-mongodb-native
const mockDisconnectHandler = {
add: () => {},
execute: () => {},
flush: () => {}
};

it('should not stall on authentication when you are connected', function(done) {
let finish = err => {
finish = () => {};
done(err);
};

test.primaryServer.setMessageHandler(request => {
const doc = request.document;
if (doc.ismaster) {
setTimeout(() => request.reply(test.primaryStates[0]));
} else if (doc.saslStart) {
finish();
}
});

test.firstSecondaryServer.setMessageHandler(request => {
const doc = request.document;
if (doc.ismaster) {
setTimeout(() => request.reply(test.firstSecondaryStates[0]), 2000);
} else if (doc.saslStart) {
finish();
}
});

const replSet = new ReplSet(
[test.primaryServer.address(), test.firstSecondaryServer.address()],
{
setName: 'rs',
haInterval: 10000,
connectionTimeout: 3000,
disconnectHandler: mockDisconnectHandler,
secondaryOnlyConnectionAllowed: true,
size: 1
}
);

replSet.once('error', finish);
replSet.once('connect', () => replSet.auth('default', 'db', 'user', 'pencil', () => {}));
replSet.connect({
readPreference: new ReadPreference('primary'),
checkServerIdentity: true,
rejectUnauthorized: true
});

setTimeout(() => finish('replicaset stalled when attempting to authenticate'), 5000);
});
});

0 comments on commit 6b4ac89

Please sign in to comment.