Beispiel #1
0
        public void AuthenticateAsync_should_not_throw_when_authentication_succeeds()
        {
            var randomStringGenerator = new ConstantRandomStringGenerator("fyko+d2lbbFgONRv9qkxdawL");
            var subject = new ScramSha1Authenticator(__credential, randomStringGenerator);

            var saslStartReply = MessageHelper.BuildSuccessReply <RawBsonDocument>(
                RawBsonDocumentHelper.FromJson("{conversationId: 1, payload: BinData(0,\"cj1meWtvK2QybGJiRmdPTlJ2OXFreGRhd0xIbytWZ2s3cXZVT0tVd3VXTElXZzRsLzlTcmFHTUhFRSxzPXJROVpZM01udEJldVAzRTFURFZDNHc9PSxpPTEwMDAw\"), done: false, ok: 1}"));
            var saslContinueReply = MessageHelper.BuildSuccessReply <RawBsonDocument>(
                RawBsonDocumentHelper.FromJson("{conversationId: 1, payload: BinData(0,\"dj1VTVdlSTI1SkQxeU5ZWlJNcFo0Vkh2aFo5ZTA9\"), done: true, ok: 1}"));

            var connection = new MockConnection(__serverId);

            connection.EnqueueReplyMessage(saslStartReply);
            connection.EnqueueReplyMessage(saslContinueReply);

            var    currentRequestId = RequestMessage.CurrentGlobalRequestId;
            Action act = () => subject.AuthenticateAsync(connection, Timeout.InfiniteTimeSpan, CancellationToken.None).Wait();

            act.ShouldNotThrow();

            var sentMessages = MessageHelper.TranslateMessagesToBsonDocuments(connection.GetSentMessages());

            sentMessages.Count.Should().Be(2);

            sentMessages[0].Should().Be("{opcode: \"query\", requestId: " + (currentRequestId + 1) + ", database: \"source\", collection: \"$cmd\", batchSize: -1, slaveOk: true, query: {saslStart: 1, mechanism: \"SCRAM-SHA-1\", payload: new BinData(0, \"biwsbj11c2VyLHI9ZnlrbytkMmxiYkZnT05Sdjlxa3hkYXdM\")}}");
            sentMessages[1].Should().Be("{opcode: \"query\", requestId: " + (currentRequestId + 2) + ", database: \"source\", collection: \"$cmd\", batchSize: -1, slaveOk: true, query: {saslContinue: 1, conversationId: 1, payload: new BinData(0, \"Yz1iaXdzLHI9ZnlrbytkMmxiYkZnT05Sdjlxa3hkYXdMSG8rVmdrN3F2VU9LVXd1V0xJV2c0bC85U3JhR01IRUUscD1NQzJUOEJ2Ym1XUmNrRHc4b1dsNUlWZ2h3Q1k9\")}}");
        }
        public void Authenticate_should_throw_an_AuthenticationException_when_authentication_fails(
            [Values("MongoConnectionException", "MongoNotPrimaryException")] string exceptionName,
            [Values(false, true)] bool async)
        {
            var subject = new ScramSha1Authenticator(__credential, serverApi: null);

            var responseException = CoreExceptionHelper.CreateException(exceptionName);
            var connection        = new MockConnection(__serverId);

            connection.EnqueueCommandResponseMessage(responseException);
            connection.Description = __descriptionCommandWireProtocol;

            Exception exception;

            if (async)
            {
                exception = Record.Exception(() => subject.AuthenticateAsync(connection, __descriptionCommandWireProtocol, CancellationToken.None).GetAwaiter().GetResult());
            }
            else
            {
                exception = Record.Exception(() => subject.Authenticate(connection, __descriptionCommandWireProtocol, CancellationToken.None));
            }

            exception.Should().BeOfType <MongoAuthenticationException>();
        }
        public void Authenticate_should_throw_when_server_provides_invalid_r_value(
            [Values(false, true)]
            bool async)
        {
            var randomStringGenerator = new ConstantRandomStringGenerator("fyko+d2lbbFgONRv9qkxdawL");
            var subject = new ScramSha1Authenticator(__credential, randomStringGenerator);

            var saslStartReply = MessageHelper.BuildReply<RawBsonDocument>(
                RawBsonDocumentHelper.FromJson("{conversationId: 1, payload: BinData(0,\"cj1meWtvLWQybGJiRmdPTlJ2OXFreGRhd0xIbytWZ2s3cXZVT0tVd3VXTElXZzRsLzlTcmFHTUhFRSxzPXJROVpZM01udEJldVAzRTFURFZDNHc9PSxpPTEwMDAw\"), done: false, ok: 1}"));

            var connection = new MockConnection(__serverId);
            connection.EnqueueReplyMessage(saslStartReply);

            Action act;
            if (async)
            {
                act = () => subject.AuthenticateAsync(connection, __description, CancellationToken.None).GetAwaiter().GetResult();
            }
            else
            {
                act = () => subject.Authenticate(connection, __description, CancellationToken.None);
            }

            act.ShouldThrow<MongoAuthenticationException>();
        }
        public void Authenticate_should_throw_when_server_provides_invalid_serverSignature(
            [Values(false, true)]
            bool async)
        {
            var randomStringGenerator = new ConstantRandomStringGenerator("fyko+d2lbbFgONRv9qkxdawL");
            var subject = new ScramSha1Authenticator(__credential, randomStringGenerator, serverApi: null);

            var saslStartReply = MessageHelper.BuildReply <RawBsonDocument>(
                RawBsonDocumentHelper.FromJson("{conversationId: 1, payload: BinData(0,'cj1meWtvK2QybGJiRmdPTlJ2OXFreGRhd0xIbytWZ2s3cXZVT0tVd3VXTElXZzRsLzlTcmFHTUhFRSxzPXJROVpZM01udEJldVAzRTFURFZDNHc9PSxpPTEwMDAw'), done: false, ok: 1}"));
            var saslContinueReply = MessageHelper.BuildReply <RawBsonDocument>(
                RawBsonDocumentHelper.FromJson("{conversationId: 1, payload: BinData(0,'dj1VTVdlSTI1SkQxeU5ZWlJNcFo0Vkh2aFo5ZTBh'), done: true, ok: 1}"));

            var connection = new MockConnection(__serverId);

            connection.EnqueueReplyMessage(saslStartReply);
            connection.EnqueueReplyMessage(saslContinueReply);

            Action act;

            if (async)
            {
                act = () => subject.AuthenticateAsync(connection, __descriptionQueryWireProtocol, CancellationToken.None).GetAwaiter().GetResult();
            }
            else
            {
                act = () => subject.Authenticate(connection, __descriptionQueryWireProtocol, CancellationToken.None);
            }

            act.ShouldThrow <MongoAuthenticationException>();
        }
        public void Authenticate_should_use_cache(
            [Values(false, true)] bool async)
        {
            var randomStringGenerator = new ConstantRandomStringGenerator("fyko+d2lbbFgONRv9qkxdawL");
            var subject = new ScramSha1Authenticator(__credential, randomStringGenerator, serverApi: null);

            var saslStartReply = MessageHelper.BuildReply <RawBsonDocument>(
                RawBsonDocumentHelper.FromJson(
                    "{conversationId: 1, payload: BinData(0,'cj1meWtvK2QybGJiRmdPTlJ2OXFreGRhd0xIbytWZ2s3cXZVT0tVd3VXTElXZzRsLzlTcmFHTUhFRSxzPXJROVpZM01udEJldVAzRTFURFZDNHc9PSxpPTEwMDAw'), done: false, ok: 1}"));
            var saslContinueReply = MessageHelper.BuildReply <RawBsonDocument>(
                RawBsonDocumentHelper.FromJson(
                    "{conversationId: 1, payload: BinData(0,'dj1VTVdlSTI1SkQxeU5ZWlJNcFo0Vkh2aFo5ZTA9'), done: true, ok: 1}"));
            var connection = new MockConnection(__serverId);

            connection.EnqueueReplyMessage(saslStartReply);
            connection.EnqueueReplyMessage(saslContinueReply);

            if (async)
            {
                subject.AuthenticateAsync(connection, __descriptionQueryWireProtocol, CancellationToken.None).GetAwaiter()
                .GetResult();
            }
            else
            {
                subject.Authenticate(connection, __descriptionQueryWireProtocol, CancellationToken.None);
            }

            SpinWait.SpinUntil(() => connection.GetSentMessages().Count >= 2, TimeSpan.FromSeconds(5)).Should()
            .BeTrue();

            subject._cache().Should().NotBe(null);
            subject._cache()._cacheKey().Should().NotBe(null);
            subject._cache()._cachedEntry().Should().NotBe(null);
        }
        public void AuthenticateAsync_should_throw_an_AuthenticationException_when_authentication_fails()
        {
            var subject = new ScramSha1Authenticator(__credential);

            var reply = MessageHelper.BuildNoDocumentsReturnedReply<RawBsonDocument>();
            var connection = new MockConnection(__serverId);
            connection.EnqueueReplyMessage(reply);

            Action act = () => subject.AuthenticateAsync(connection, __description, CancellationToken.None).Wait();

            act.ShouldThrow<MongoAuthenticationException>();
        }
        public void Authenticate_should_send_serverApi_with_command_wire_protocol_if_serverApi_is_provided(
            [Values(false, true)] bool useServerApi,
            [Values(false, true)] bool async)
        {
            var serverApi = useServerApi ? new ServerApi(ServerApiVersion.V1, true, true) : null;
            var randomStringGenerator = new ConstantRandomStringGenerator("fyko+d2lbbFgONRv9qkxdawL");

            var subject = new ScramSha1Authenticator(__credential, randomStringGenerator, serverApi);

            var connection = new MockConnection(__serverId);
            var saslStartReply = RawBsonDocumentHelper.FromJson("{ conversationId : 1, payload : BinData(0,'cj1meWtvK2QybGJiRmdPTlJ2OXFreGRhd0xIbytWZ2s3cXZVT0tVd3VXTElXZzRsLzlTcmFHTUhFRSxzPXJROVpZM01udEJldVAzRTFURFZDNHc9PSxpPTEwMDAw'), done : false, ok : 1 }");
            var saslContinueReply = RawBsonDocumentHelper.FromJson("{ conversationId : 1, payload : BinData(0,'dj1VTVdlSTI1SkQxeU5ZWlJNcFo0Vkh2aFo5ZTA9'), done : true, ok : 1}");
            if (useServerApi)
            {
                connection.EnqueueCommandResponseMessage(MessageHelper.BuildCommandResponse(saslStartReply));
                connection.EnqueueCommandResponseMessage(MessageHelper.BuildCommandResponse(saslContinueReply));
            }
            else
            {
                connection.EnqueueReplyMessage(MessageHelper.BuildReply(saslStartReply));
                connection.EnqueueReplyMessage(MessageHelper.BuildReply(saslContinueReply));
            }

            connection.Description = __descriptionQueryWireProtocol;

            if (async)
            {
                subject.AuthenticateAsync(connection, __descriptionQueryWireProtocol, CancellationToken.None).GetAwaiter().GetResult();
            }
            else
            {
                subject.Authenticate(connection, __descriptionQueryWireProtocol, CancellationToken.None);
            }

            SpinWait.SpinUntil(() => connection.GetSentMessages().Count >= 2, TimeSpan.FromSeconds(5)).Should().BeTrue();

            var sentMessages = MessageHelper.TranslateMessagesToBsonDocuments(connection.GetSentMessages());
            sentMessages.Count.Should().Be(2);

            var actualRequestId0 = sentMessages[0]["requestId"].AsInt32;
            var actualRequestId1 = sentMessages[1]["requestId"].AsInt32;

            if (useServerApi)
            {
                sentMessages[0].Should().Be($"{{opcode : \"opmsg\", requestId : {actualRequestId0}, responseTo : 0, sections : [{{ payloadType : 0, document : {{ saslStart : 1, mechanism : \"SCRAM-SHA-1\", payload : new BinData(0, \"biwsbj11c2VyLHI9ZnlrbytkMmxiYkZnT05Sdjlxa3hkYXdM\"), options : {{ skipEmptyExchange : true }}, \"$db\" : \"source\", apiVersion : \"1\", apiStrict : true, apiDeprecationErrors : true }} }}]}}");
                sentMessages[1].Should().Be($"{{opcode : \"opmsg\", requestId : {actualRequestId1}, responseTo : 0, sections : [{{ payloadType : 0, document : {{ saslContinue : 1, conversationId : 1, payload : new BinData(0, \"Yz1iaXdzLHI9ZnlrbytkMmxiYkZnT05Sdjlxa3hkYXdMSG8rVmdrN3F2VU9LVXd1V0xJV2c0bC85U3JhR01IRUUscD1NQzJUOEJ2Ym1XUmNrRHc4b1dsNUlWZ2h3Q1k9\"), \"$db\" : \"source\", apiVersion : \"1\", apiStrict : true, apiDeprecationErrors : true }} }}]}}");
            }
            else
            {
                sentMessages[0].Should().Be($"{{ opcode : \"query\", requestId : {actualRequestId0}, database : \"source\", collection : \"$cmd\", batchSize : -1, slaveOk : true, query : {{ saslStart : 1, mechanism : \"SCRAM-SHA-1\", payload : new BinData(0, \"biwsbj11c2VyLHI9ZnlrbytkMmxiYkZnT05Sdjlxa3hkYXdM\"), options : {{ \"skipEmptyExchange\" : true }} }} }}");
                sentMessages[1].Should().Be($"{{ opcode : \"query\", requestId : {actualRequestId1}, database : \"source\", collection : \"$cmd\", batchSize : -1, slaveOk : true, query : {{ saslContinue : 1, conversationId : 1, payload : new BinData(0, \"Yz1iaXdzLHI9ZnlrbytkMmxiYkZnT05Sdjlxa3hkYXdMSG8rVmdrN3F2VU9LVXd1V0xJV2c0bC85U3JhR01IRUUscD1NQzJUOEJ2Ym1XUmNrRHc4b1dsNUlWZ2h3Q1k9\") }} }}");
            }
        }
Beispiel #8
0
        public void AuthenticateAsync_should_throw_an_AuthenticationException_when_authentication_fails()
        {
            var subject = new ScramSha1Authenticator(__credential);

            var reply      = MessageHelper.BuildNoDocumentsReturnedReply <RawBsonDocument>();
            var connection = new MockConnection(__serverId);

            connection.EnqueueReplyMessage(reply);

            Action act = () => subject.AuthenticateAsync(connection, Timeout.InfiniteTimeSpan, CancellationToken.None).Wait();

            act.ShouldThrow <MongoAuthenticationException>();
        }
        // methods
        public Task AuthenticateAsync(IConnection connection, TimeSpan timeout, CancellationToken cancellationToken)
        {
            IAuthenticator authenticator;

            if (connection.Description.BuildInfoResult.ServerVersion >= __scramVersionRequirement)
            {
                authenticator = new ScramSha1Authenticator(_credential, _randomStringGenerator);
            }
            else
            {
                authenticator = new MongoDBCRAuthenticator(_credential);
            }

            return(authenticator.AuthenticateAsync(connection, timeout, cancellationToken));
        }
        public void AuthenticateAsync_should_throw_when_server_provides_invalid_r_value()
        {
            var randomStringGenerator = new ConstantRandomStringGenerator("fyko+d2lbbFgONRv9qkxdawL");
            var subject = new ScramSha1Authenticator(__credential, randomStringGenerator);

            var saslStartReply = MessageHelper.BuildSuccessReply<RawBsonDocument>(
                RawBsonDocumentHelper.FromJson("{conversationId: 1, payload: BinData(0,\"cj1meWtvLWQybGJiRmdPTlJ2OXFreGRhd0xIbytWZ2s3cXZVT0tVd3VXTElXZzRsLzlTcmFHTUhFRSxzPXJROVpZM01udEJldVAzRTFURFZDNHc9PSxpPTEwMDAw\"), done: false, ok: 1}"));

            var connection = new MockConnection(__serverId);
            connection.EnqueueReplyMessage(saslStartReply);

            var currentRequestId = RequestMessage.CurrentGlobalRequestId;
            Action act = () => subject.AuthenticateAsync(connection, Timeout.InfiniteTimeSpan, CancellationToken.None).Wait();
            act.ShouldThrow<MongoAuthenticationException>();
        }
Beispiel #11
0
        public void AuthenticateAsync_should_throw_when_server_provides_invalid_r_value()
        {
            var randomStringGenerator = new ConstantRandomStringGenerator("fyko+d2lbbFgONRv9qkxdawL");
            var subject = new ScramSha1Authenticator(__credential, randomStringGenerator);

            var saslStartReply = MessageHelper.BuildSuccessReply <RawBsonDocument>(
                RawBsonDocumentHelper.FromJson("{conversationId: 1, payload: BinData(0,\"cj1meWtvLWQybGJiRmdPTlJ2OXFreGRhd0xIbytWZ2s3cXZVT0tVd3VXTElXZzRsLzlTcmFHTUhFRSxzPXJROVpZM01udEJldVAzRTFURFZDNHc9PSxpPTEwMDAw\"), done: false, ok: 1}"));

            var connection = new MockConnection(__serverId);

            connection.EnqueueReplyMessage(saslStartReply);

            var    currentRequestId = RequestMessage.CurrentGlobalRequestId;
            Action act = () => subject.AuthenticateAsync(connection, Timeout.InfiniteTimeSpan, CancellationToken.None).Wait();

            act.ShouldThrow <MongoAuthenticationException>();
        }
        // methods
        /// <inheritdoc/>
        public Task AuthenticateAsync(IConnection connection, ConnectionDescription description, CancellationToken cancellationToken)
        {
            Ensure.IsNotNull(connection, "connection");
            Ensure.IsNotNull(description, "description");

            IAuthenticator authenticator;
            if (description.BuildInfoResult.ServerVersion >= __scramVersionRequirement)
            {
                authenticator = new ScramSha1Authenticator(_credential, _randomStringGenerator);
            }
            else
            {
                authenticator = new MongoDBCRAuthenticator(_credential);
            }

            return authenticator.AuthenticateAsync(connection, description, cancellationToken);
        }
Beispiel #13
0
        // methods
        /// <inheritdoc/>
        public Task AuthenticateAsync(IConnection connection, ConnectionDescription description, CancellationToken cancellationToken)
        {
            Ensure.IsNotNull(connection, "connection");
            Ensure.IsNotNull(description, "description");

            IAuthenticator authenticator;

            if (description.BuildInfoResult.ServerVersion >= __scramVersionRequirement)
            {
                authenticator = new ScramSha1Authenticator(_credential, _randomStringGenerator);
            }
            else
            {
                authenticator = new MongoDBCRAuthenticator(_credential);
            }

            return(authenticator.AuthenticateAsync(connection, description, cancellationToken));
        }
        public void Authenticate_should_not_throw_when_authentication_succeeds(
            [Values(false, true)]
            bool async)
        {
            var randomStringGenerator = new ConstantRandomStringGenerator("fyko+d2lbbFgONRv9qkxdawL");
            var subject = new ScramSha1Authenticator(__credential, randomStringGenerator);

            var saslStartReply = MessageHelper.BuildReply<RawBsonDocument>(
                RawBsonDocumentHelper.FromJson("{conversationId: 1, payload: BinData(0,\"cj1meWtvK2QybGJiRmdPTlJ2OXFreGRhd0xIbytWZ2s3cXZVT0tVd3VXTElXZzRsLzlTcmFHTUhFRSxzPXJROVpZM01udEJldVAzRTFURFZDNHc9PSxpPTEwMDAw\"), done: false, ok: 1}"));
            var saslContinueReply = MessageHelper.BuildReply<RawBsonDocument>(
                RawBsonDocumentHelper.FromJson("{conversationId: 1, payload: BinData(0,\"dj1VTVdlSTI1SkQxeU5ZWlJNcFo0Vkh2aFo5ZTA9\"), done: true, ok: 1}"));

            var connection = new MockConnection(__serverId);
            connection.EnqueueReplyMessage(saslStartReply);
            connection.EnqueueReplyMessage(saslContinueReply);

            var expectedRequestId = RequestMessage.CurrentGlobalRequestId + 1;

            Action act;
            if (async)
            {
                act = () => subject.AuthenticateAsync(connection, __description, CancellationToken.None).GetAwaiter().GetResult();
            }
            else
            {
                act = () => subject.Authenticate(connection, __description, CancellationToken.None);
            }

            act.ShouldNotThrow();
            SpinWait.SpinUntil(() => connection.GetSentMessages().Count >= 2, 100).Should().BeTrue();

            var sentMessages = MessageHelper.TranslateMessagesToBsonDocuments(connection.GetSentMessages());
            sentMessages.Count.Should().Be(2);

            var actualRequestId0 = sentMessages[0]["requestId"].AsInt32;
            var actualRequestId1 = sentMessages[1]["requestId"].AsInt32;
            actualRequestId0.Should().BeInRange(expectedRequestId, expectedRequestId + 10);
            actualRequestId1.Should().BeInRange(actualRequestId0 + 1, actualRequestId0 + 11);

            sentMessages[0].Should().Be("{opcode: \"query\", requestId: " + actualRequestId0 + ", database: \"source\", collection: \"$cmd\", batchSize: -1, slaveOk: true, query: {saslStart: 1, mechanism: \"SCRAM-SHA-1\", payload: new BinData(0, \"biwsbj11c2VyLHI9ZnlrbytkMmxiYkZnT05Sdjlxa3hkYXdM\")}}");
            sentMessages[1].Should().Be("{opcode: \"query\", requestId: " + actualRequestId1 + ", database: \"source\", collection: \"$cmd\", batchSize: -1, slaveOk: true, query: {saslContinue: 1, conversationId: 1, payload: new BinData(0, \"Yz1iaXdzLHI9ZnlrbytkMmxiYkZnT05Sdjlxa3hkYXdMSG8rVmdrN3F2VU9LVXd1V0xJV2c0bC85U3JhR01IRUUscD1NQzJUOEJ2Ym1XUmNrRHc4b1dsNUlWZ2h3Q1k9\")}}");
        }
        public void Authenticate_should_throw_an_AuthenticationException_when_authentication_fails(
            [Values(false, true)]
            bool async)
        {
            var subject = new ScramSha1Authenticator(__credential);

            var reply = MessageHelper.BuildNoDocumentsReturnedReply<RawBsonDocument>();
            var connection = new MockConnection(__serverId);
            connection.EnqueueReplyMessage(reply);

            Action act;
            if (async)
            {
                act = () => subject.AuthenticateAsync(connection, __description, CancellationToken.None).GetAwaiter().GetResult();
            }
            else
            {
                act = () => subject.Authenticate(connection, __description, CancellationToken.None);
            }

            act.ShouldThrow<MongoAuthenticationException>();
        }
        public void Authenticate_should_throw_an_AuthenticationException_when_authentication_fails(
            [Values(false, true)]
            bool async)
        {
            var subject = new ScramSha1Authenticator(__credential, serverApi: null);

            var reply      = MessageHelper.BuildNoDocumentsReturnedReply <RawBsonDocument>();
            var connection = new MockConnection(__serverId);

            connection.EnqueueReplyMessage(reply);

            Action act;

            if (async)
            {
                act = () => subject.AuthenticateAsync(connection, __descriptionQueryWireProtocol, CancellationToken.None).GetAwaiter().GetResult();
            }
            else
            {
                act = () => subject.Authenticate(connection, __descriptionQueryWireProtocol, CancellationToken.None);
            }

            act.ShouldThrow <MongoAuthenticationException>();
        }
        public void Authenticate_should_not_throw_when_authentication_succeeds(
            [Values(false, true)] bool useSpeculativeAuthenticate,
            [Values(false, true)] bool useLongAuthentication,
            [Values(false, true)] bool async)
        {
            var randomStringGenerator = new ConstantRandomStringGenerator("fyko+d2lbbFgONRv9qkxdawL");
            var subject = new ScramSha1Authenticator(__credential, randomStringGenerator, serverApi: null);

            var saslStartReply = MessageHelper.BuildReply <RawBsonDocument>(
                RawBsonDocumentHelper.FromJson("{ conversationId : 1, payload : BinData(0,'cj1meWtvK2QybGJiRmdPTlJ2OXFreGRhd0xIbytWZ2s3cXZVT0tVd3VXTElXZzRsLzlTcmFHTUhFRSxzPXJROVpZM01udEJldVAzRTFURFZDNHc9PSxpPTEwMDAw'), done : false, ok : 1}"));
            var saslContinueReply = MessageHelper.BuildReply <RawBsonDocument>(RawBsonDocumentHelper.FromJson(
                                                                                   @"{ conversationId : 1,
                    payload : BinData(0,'dj1VTVdlSTI1SkQxeU5ZWlJNcFo0Vkh2aFo5ZTA9')," +
                                                                                   $"  done : {new BsonBoolean(!useLongAuthentication)}, " +
                                                                                   @"  ok : 1}"));
            var saslLastStepReply = MessageHelper.BuildReply <RawBsonDocument>(RawBsonDocumentHelper.FromJson(
                                                                                   @"{ conversationId : 1,
                    payload : BinData(0,''),
                    done : true,
                    ok : 1 }"));

            var connection     = new MockConnection(__serverId);
            var isMasterResult = (BsonDocument)__descriptionQueryWireProtocol.IsMasterResult.Wrapped.Clone();

            if (useSpeculativeAuthenticate)
            {
                isMasterResult.Add("speculativeAuthenticate", saslStartReply.Documents[0].ToBsonDocument());
            }

            /* set buildInfoResult to 3.4 to force authenticator to use Query Message Wire Protocol because MockConnection
             * does not support OP_MSG */
            connection.Description = new ConnectionDescription(
                __descriptionQueryWireProtocol.ConnectionId, new IsMasterResult(isMasterResult), new BuildInfoResult(new BsonDocument("version", "3.4")));

            BsonDocument isMasterCommand = null;

            if (useSpeculativeAuthenticate)
            {
                // Call CustomizeIsMasterCommand so that the authenticator thinks its started to speculatively
                // authenticate
                isMasterCommand = subject.CustomizeInitialIsMasterCommand(new BsonDocument {
                    { "isMaster", 1 }
                });
            }
            else
            {
                connection.EnqueueReplyMessage(saslStartReply);
            }

            connection.EnqueueReplyMessage(saslContinueReply);
            if (useLongAuthentication)
            {
                connection.EnqueueReplyMessage(saslLastStepReply);
            }

            Exception exception;

            if (async)
            {
                exception = Record.Exception(
                    () => subject.AuthenticateAsync(connection, connection.Description, CancellationToken.None)
                    .GetAwaiter().GetResult());
            }
            else
            {
                exception = Record.Exception(
                    () => subject.Authenticate(connection, connection.Description, CancellationToken.None));
            }

            exception.Should().BeNull();
            var expectedSentMessageCount = 3 - (useLongAuthentication ? 0 : 1) - (useSpeculativeAuthenticate ? 1 : 0);

            SpinWait.SpinUntil(
                () => connection.GetSentMessages().Count >= expectedSentMessageCount,
                TimeSpan.FromSeconds(5)
                ).Should().BeTrue();

            var sentMessages = MessageHelper.TranslateMessagesToBsonDocuments(connection.GetSentMessages());

            sentMessages.Count.Should().Be(expectedSentMessageCount);

            var actualRequestIds = sentMessages.Select(m => m["requestId"].AsInt32).ToList();

            var expectedMessages = new List <BsonDocument>();

            var saslStartMessage = BsonDocument.Parse(
                @"{ opcode : 'query'," +
                $"  requestId : {actualRequestIds[0]}, " +
                @"  database : 'source',
                    collection : '$cmd',
                    batchSize : -1,
                    slaveOk : true,
                    query : { saslStart : 1,
                             mechanism : 'SCRAM-SHA-1'," +
                $"           payload : new BinData(0, 'biwsbj11c2VyLHI9ZnlrbytkMmxiYkZnT05Sdjlxa3hkYXdM')" +
                @"           options : { skipEmptyExchange: true }}}");

            if (!useSpeculativeAuthenticate)
            {
                expectedMessages.Add(saslStartMessage);
            }

            var saslContinueMessage = BsonDocument.Parse(
                @"{ opcode : 'query'," +
                $"  requestId : {(useSpeculativeAuthenticate ? actualRequestIds[0] : actualRequestIds[1])}," +
                @"  database : 'source',
                    collection : '$cmd',
                    batchSize : -1,
                    slaveOk : true,
                    query : { saslContinue : 1,
                             conversationId : 1, " +
                $"           payload : new BinData(0, 'Yz1iaXdzLHI9ZnlrbytkMmxiYkZnT05Sdjlxa3hkYXdMSG8rVmdrN3F2VU9LVXd1V0xJV2c0bC85U3JhR01IRUUscD1NQzJUOEJ2Ym1XUmNrRHc4b1dsNUlWZ2h3Q1k9')}}}}");

            expectedMessages.Add(saslContinueMessage);

            if (useLongAuthentication)
            {
                var saslOptionalFinalMessage = BsonDocument.Parse(
                    @"{opcode : 'query'," +
                    $" requestId : {(useSpeculativeAuthenticate ? actualRequestIds[1] : actualRequestIds[2])}," +
                    @" database : 'source',
                        collection : '$cmd',
                        batchSize : -1,
                        slaveOk : true,
                        query : { saslContinue : 1,
                                 conversationId : 1, " +
                    $"          payload : new BinData(0, '')}}}}");
                expectedMessages.Add(saslOptionalFinalMessage);
            }

            sentMessages.Should().Equal(expectedMessages);
            if (useSpeculativeAuthenticate)
            {
                isMasterCommand.Should().Contain("speculativeAuthenticate");
                var speculativeAuthenticateDocument         = isMasterCommand["speculativeAuthenticate"].AsBsonDocument;
                var expectedSpeculativeAuthenticateDocument =
                    saslStartMessage["query"].AsBsonDocument.Add("db", __credential.Source);
                speculativeAuthenticateDocument.Should().Be(expectedSpeculativeAuthenticateDocument);
            }
        }
        public void Authenticate_should_not_throw_when_authentication_succeeds(
            [Values(false, true)] bool useLongAuthentication,
            [Values(false, true)] bool async)
        {
            var randomStringGenerator = new ConstantRandomStringGenerator("fyko+d2lbbFgONRv9qkxdawL");
            var subject = new ScramSha1Authenticator(__credential, randomStringGenerator);

            var saslStartReply = MessageHelper.BuildReply <RawBsonDocument>(
                RawBsonDocumentHelper.FromJson("{conversationId: 1, payload: BinData(0,\"cj1meWtvK2QybGJiRmdPTlJ2OXFreGRhd0xIbytWZ2s3cXZVT0tVd3VXTElXZzRsLzlTcmFHTUhFRSxzPXJROVpZM01udEJldVAzRTFURFZDNHc9PSxpPTEwMDAw\"), done: false, ok: 1}"));
            var saslContinueReply = MessageHelper.BuildReply <RawBsonDocument>(RawBsonDocumentHelper.FromJson(
                                                                                   @"{conversationId: 1,
                   payload: BinData(0,""dj1VTVdlSTI1SkQxeU5ZWlJNcFo0Vkh2aFo5ZTA9"")," +
                                                                                   $" done: {new BsonBoolean(!useLongAuthentication)}, " +
                                                                                   @"  ok: 1}"));
            var saslLastStepReply = MessageHelper.BuildReply <RawBsonDocument>(RawBsonDocumentHelper.FromJson(
                                                                                   @"{conversationId: 1," +
                                                                                   $" payload: BinData(0,\"\")," +
                                                                                   @" done: true,
                   ok: 1}"));

            var connection = new MockConnection(__serverId);

            connection.EnqueueReplyMessage(saslStartReply);
            connection.EnqueueReplyMessage(saslContinueReply);
            if (useLongAuthentication)
            {
                connection.EnqueueReplyMessage(saslLastStepReply);
            }
            var expectedRequestId = RequestMessage.CurrentGlobalRequestId + 1;

            Action act;

            if (async)
            {
                act = () => subject.AuthenticateAsync(connection, __description, CancellationToken.None).GetAwaiter().GetResult();
            }
            else
            {
                act = () => subject.Authenticate(connection, __description, CancellationToken.None);
            }

            act.ShouldNotThrow();
            var expectedSentMessageCount = useLongAuthentication ? 3 : 2;

            SpinWait.SpinUntil(
                () => connection.GetSentMessages().Count >= expectedSentMessageCount,
                TimeSpan.FromSeconds(5)
                ).Should().BeTrue();

            var sentMessages = MessageHelper.TranslateMessagesToBsonDocuments(connection.GetSentMessages());

            sentMessages.Count.Should().Be(expectedSentMessageCount);

            var actualRequestIds = sentMessages.Select(m => m["requestId"].AsInt32).ToList();

            for (var i = 0; i != actualRequestIds.Count; ++i)
            {
                actualRequestIds[i].Should().BeInRange(expectedRequestId + i, expectedRequestId + 10 + i);
            }

            sentMessages[0].Should().Be(
                $"{{opcode: \"query\", " +
                $"  requestId: {actualRequestIds[0]}, " +
                $"  database: \"source\", collection: \"$cmd\", batchSize: -1, slaveOk: true, " +
                $"  query: {{saslStart: 1, mechanism: \"SCRAM-SHA-1\", " +
                $"           payload: new BinData(0, \"biwsbj11c2VyLHI9ZnlrbytkMmxiYkZnT05Sdjlxa3hkYXdM\")" +
                @"           options: { skipEmptyExchange: true }}}");
            sentMessages[1].Should().Be("{opcode: \"query\", requestId: " + actualRequestIds[1] + ", database: \"source\", collection: \"$cmd\", batchSize: -1, slaveOk: true, query: {saslContinue: 1, conversationId: 1, payload: new BinData(0, \"Yz1iaXdzLHI9ZnlrbytkMmxiYkZnT05Sdjlxa3hkYXdMSG8rVmdrN3F2VU9LVXd1V0xJV2c0bC85U3JhR01IRUUscD1NQzJUOEJ2Ym1XUmNrRHc4b1dsNUlWZ2h3Q1k9\")}}");
            if (useLongAuthentication)
            {
                sentMessages[2].Should().Be(
                    @"{opcode: ""query""," +
                    $" requestId: {actualRequestIds[2]}," +
                    @" database: ""source"",
                       collection: ""$cmd"",
                       batchSize: -1,
                       slaveOk: true,
                       query: {saslContinue: 1,
                               conversationId: 1, " +
                    $"         payload: new BinData(0, \"\")}}}}");
            }
        }
        public void Authenticate_should_not_throw_when_authentication_succeeds(
            [Values(false, true)] bool useSpeculativeAuthenticate,
            [Values(false, true)] bool useLongAuthentication,
            [Values(false, true)] bool async)
        {
            var randomStringGenerator = new ConstantRandomStringGenerator("fyko+d2lbbFgONRv9qkxdawL");
            var subject = new ScramSha1Authenticator(__credential, randomStringGenerator, serverApi: null);

            var saslStartResponse = MessageHelper.BuildCommandResponse(
                RawBsonDocumentHelper.FromJson("{ conversationId : 1, payload : BinData(0,'cj1meWtvK2QybGJiRmdPTlJ2OXFreGRhd0xIbytWZ2s3cXZVT0tVd3VXTElXZzRsLzlTcmFHTUhFRSxzPXJROVpZM01udEJldVAzRTFURFZDNHc9PSxpPTEwMDAw'), done : false, ok : 1}"));
            var saslContinueResponse = MessageHelper.BuildCommandResponse(RawBsonDocumentHelper.FromJson(
                                                                              @"{ conversationId : 1,
                    payload : BinData(0,'dj1VTVdlSTI1SkQxeU5ZWlJNcFo0Vkh2aFo5ZTA9')," +
                                                                              $"  done : {new BsonBoolean(!useLongAuthentication)}, " +
                                                                              @"  ok : 1}"));
            var saslLastStepResponse = MessageHelper.BuildCommandResponse(RawBsonDocumentHelper.FromJson(
                                                                              @"{ conversationId : 1,
                    payload : BinData(0,''),
                    done : true,
                    ok : 1 }"));

            var connection  = new MockConnection(__serverId);
            var helloResult = (BsonDocument)__descriptionCommandWireProtocol.HelloResult.Wrapped.Clone();

            if (useSpeculativeAuthenticate)
            {
                helloResult.Add("speculativeAuthenticate", ((Type0CommandMessageSection <RawBsonDocument>)saslStartResponse.WrappedMessage.Sections[0]).Document);
            }

            connection.Description = new ConnectionDescription(__descriptionCommandWireProtocol.ConnectionId, new HelloResult(helloResult));

            BsonDocument helloCommand = null;

            if (useSpeculativeAuthenticate)
            {
                // Call CustomizeInitialHelloCommand so that the authenticator thinks its started to speculatively
                // authenticate
                helloCommand = subject.CustomizeInitialHelloCommand(new BsonDocument {
                    { OppressiveLanguageConstants.LegacyHelloCommandName, 1 }
                });
            }
            else
            {
                connection.EnqueueCommandResponseMessage(saslStartResponse);
            }

            connection.EnqueueCommandResponseMessage(saslContinueResponse);
            if (useLongAuthentication)
            {
                connection.EnqueueCommandResponseMessage(saslLastStepResponse);
            }

            Exception exception;

            if (async)
            {
                exception = Record.Exception(
                    () => subject.AuthenticateAsync(connection, connection.Description, CancellationToken.None)
                    .GetAwaiter().GetResult());
            }
            else
            {
                exception = Record.Exception(
                    () => subject.Authenticate(connection, connection.Description, CancellationToken.None));
            }

            exception.Should().BeNull();
            var expectedSentMessageCount = 3 - (useLongAuthentication ? 0 : 1) - (useSpeculativeAuthenticate ? 1 : 0);

            SpinWait.SpinUntil(
                () => connection.GetSentMessages().Count >= expectedSentMessageCount,
                TimeSpan.FromSeconds(5)
                ).Should().BeTrue();

            var sentMessages = MessageHelper.TranslateMessagesToBsonDocuments(connection.GetSentMessages());

            sentMessages.Count.Should().Be(expectedSentMessageCount);

            var actualRequestIds = sentMessages.Select(m => m["requestId"].AsInt32).ToList();

            var expectedMessages = new List <BsonDocument>();

            var saslStartMessage = BsonDocument.Parse(@$ "
            {{
                opcode : 'opmsg',
                requestId : {actualRequestIds[0]},