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(_clientNonce);
            var subject = new ScramSha256Authenticator(__credential, randomStringGenerator, serverApi: null);

            var saslStartResponse = MessageHelper.BuildCommandResponse(RawBsonDocumentHelper.FromJson(
                                                                           @"{ conversationId : 1," +
                                                                           $"  payload : BinData(0,'{ToUtf8Base64(__serverResponse1)}')," +
                                                                           @"  done : false,
                    ok : 1 }"));
            var saslContinueResponse = MessageHelper.BuildCommandResponse(RawBsonDocumentHelper.FromJson(
                                                                              @"{ conversationId : 1," +
                                                                              $"  payload : BinData(0,'{ToUtf8Base64(__serverResponse2)}')," +
                                                                              $"  done : {new BsonBoolean(!useLongAuthentication)}," +
                                                                              @"  ok : 1 }"));
            var saslLastStepResponse = MessageHelper.BuildCommandResponse(RawBsonDocumentHelper.FromJson(
                                                                              @"{ conversationId : 1," +
                                                                              $"  payload : BinData(0,'{ToUtf8Base64(__serverOptionalFinalResponse)}')," +
                                                                              @"  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)
            {
                // We must 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);
            }

            var expectedRequestId = RequestMessage.CurrentGlobalRequestId + 1;

            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();

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

            var expectedMessages = new List <BsonDocument>();

            var saslStartMessage = BsonDocument.Parse(@$ "
            {{
                opcode : 'opmsg',
                requestId : {actualRequestIds[0]},
Esempio n. 2
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(_clientNonce);
            var subject = new ScramSha256Authenticator(__credential, randomStringGenerator, serverApi: null);

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

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

            if (useSpeculativeAuthenticate)
            {
                helloResult.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 HelloResult(helloResult),
                new BuildInfoResult(new BsonDocument("version", "3.4")));

            BsonDocument helloCommand = null;

            if (useSpeculativeAuthenticate)
            {
                // We must call CustomizeInitialHelloCommand so that the authenticator thinks its started to speculatively
                // authenticate
                helloCommand = subject.CustomizeInitialHelloCommand(new BsonDocument {
                    { OppressiveLanguageConstants.LegacyHelloCommandName, 1 }
                });
            }
            else
            {
                connection.EnqueueReplyMessage(saslStartReply);
            }

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

            var expectedRequestId = RequestMessage.CurrentGlobalRequestId + 1;

            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();

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

            var expectedMessages = new List <BsonDocument>();

            var saslStartMessage = BsonDocument.Parse(
                @"{ opcode : 'query'," +
                $"  requestId : {actualRequestIds[0]}," +
                @"  database : 'source',
                    collection : '$cmd',
                    batchSize : -1,
                    secondaryOk : true,
                    query : { saslStart : 1,
                              mechanism : 'SCRAM-SHA-256'," +
                $"            payload : new BinData(0, '{ToUtf8Base64(__clientRequest1)}')" +
                @"            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,
                    secondaryOk : true,
                    query : { saslContinue : 1,
                              conversationId : 1, " +
                $"            payload : new BinData(0, \"{ToUtf8Base64(__clientRequest2)}\")}}}}");

            expectedMessages.Add(saslContinueMessage);

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

            sentMessages.Should().Equal(expectedMessages);
            if (useSpeculativeAuthenticate)
            {
                helloCommand.Should().Contain("speculativeAuthenticate");
                var speculativeAuthenticateDocument         = helloCommand["speculativeAuthenticate"].AsBsonDocument;
                var expectedSpeculativeAuthenticateDocument =
                    saslStartMessage["query"].AsBsonDocument.Add("db", __credential.Source);
                speculativeAuthenticateDocument.Should().Be(expectedSpeculativeAuthenticateDocument);
            }
        }