From c2bdc19d3e05034efeb72596f746134df15b351f Mon Sep 17 00:00:00 2001 From: Oleksandr Poliakov Date: Fri, 28 Feb 2025 10:55:23 -0800 Subject: [PATCH 1/2] CSHARP-4961: Rearchitect User Acquisition in Authentication and Authorization Workflow --- .../Core/Connections/HelloResultTests.cs | 24 +++++ .../MongoDbHandshakeProseTests.cs | 98 +++++++++++++++++++ 2 files changed, 122 insertions(+) create mode 100644 tests/MongoDB.Driver.Tests/Specifications/mongodb-handshake/MongoDbHandshakeProseTests.cs diff --git a/tests/MongoDB.Driver.Tests/Core/Connections/HelloResultTests.cs b/tests/MongoDB.Driver.Tests/Core/Connections/HelloResultTests.cs index 0d0ac28af79..1998bf0df87 100644 --- a/tests/MongoDB.Driver.Tests/Core/Connections/HelloResultTests.cs +++ b/tests/MongoDB.Driver.Tests/Core/Connections/HelloResultTests.cs @@ -107,6 +107,18 @@ public void ElectionId_should_parse_document_correctly(string json, string expec subject.ElectionId.Should().Be(expected); } + [Theory] + [InlineData("{ }", false)] + [InlineData("{ saslSupportedMechs : [] }", true)] + [InlineData("{ saslSupportedMechs : ['SCRAM-SHA-128'] }", true)] + [InlineData("{ saslSupportedMechs : ['unknown'] }", true)] + public void HasSaslSupportedMechs_should_parse_document_correctly(string json, bool expected) + { + var subject = new HelloResult(BsonDocument.Parse(json)); + + subject.HasSaslSupportedMechs.Should().Be(expected); + } + [Theory] [InlineData("{ lastWrite : { lastWriteDate : ISODate(\"2015-01-01T00:00:00Z\") } }", 2015)] [InlineData("{ lastWrite : { lastWriteDate : ISODate(\"2016-01-01T00:00:00Z\") } }", 2016)] @@ -205,6 +217,18 @@ public void Me_should_parse_document_correctly(string json, string expectedEndPo subject.Me.Should().Be(endPoint); } + [Theory] + [InlineData("{ }", new string[0])] + [InlineData("{ saslSupportedMechs : ['SCRAM-SHA-128'] }", new[] { "SCRAM-SHA-128" })] + [InlineData("{ saslSupportedMechs : ['SCRAM-SHA-128', 'SCRAM-SHA-256'] }", new[] { "SCRAM-SHA-128", "SCRAM-SHA-256" })] + [InlineData("{ saslSupportedMechs : ['unknown'] }", new[] { "unknown" })] + public void SaslSupportedMechs_should_parse_document_correctly(string json, string[] expectedMechs) + { + var subject = new HelloResult(BsonDocument.Parse(json)); + + subject.SaslSupportedMechs.Should().BeEquivalentTo(expectedMechs); + } + [Theory] [InlineData("{ ok: 1, isreplicaset: true, setName: \"awesome\", isWritablePrimary: true }", ServerType.ReplicaSetGhost)] [InlineData("{ ok: 1, setName: \"awesome\", " + OppressiveLanguageConstants.LegacyHelloResponseIsWritablePrimaryFieldName + ": true }", ServerType.ReplicaSetPrimary)] diff --git a/tests/MongoDB.Driver.Tests/Specifications/mongodb-handshake/MongoDbHandshakeProseTests.cs b/tests/MongoDB.Driver.Tests/Specifications/mongodb-handshake/MongoDbHandshakeProseTests.cs new file mode 100644 index 00000000000..482a9d7b05f --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/mongodb-handshake/MongoDbHandshakeProseTests.cs @@ -0,0 +1,98 @@ +/* Copyright 2010-present MongoDB Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System.Net; +using System.Threading; +using System.Threading.Tasks; +using FluentAssertions; +using MongoDB.Bson; +using MongoDB.Bson.TestHelpers; +using MongoDB.Driver.Core; +using MongoDB.Driver.Core.Clusters; +using MongoDB.Driver.Core.Configuration; +using MongoDB.Driver.Core.Connections; +using MongoDB.Driver.Core.Misc; +using MongoDB.Driver.Core.Servers; +using MongoDB.Driver.Core.TestHelpers.Logging; +using MongoDB.TestHelpers.XunitExtensions; +using Moq; +using Xunit; +using Xunit.Abstractions; + +namespace MongoDB.Driver.Tests.Specifications.mongodb_handshake +{ + public class MongoDbHandshakeProseTests : LoggableTestClass + { + // https://github.com/mongodb/specifications/blob/75027a8e91ff50778aed2ad5a67c005f2694705f/source/mongodb-handshake/tests/README.md?plain=1#L77 + public MongoDbHandshakeProseTests(ITestOutputHelper output) : base(output) + { + } + + [Theory] + [ParameterAttributeData] + public async Task DriverAcceptsArbitraryAuthMechanism([Values(false, true)] bool async) + { + var capturedEvents = new EventCapturer(); + var mockStreamFactory = new Mock(); + var endPoint = new DnsEndPoint("localhost", 27017); + var serverId = new ServerId(new ClusterId(), endPoint); + var connectionId = new ConnectionId(serverId); + var helloResult = new HelloResult(BsonDocument.Parse("{ ok: 1, saslSupportedMechs : ['arbitrary string'] }")); + var connectionDescription = new ConnectionDescription(connectionId, helloResult); + var connectionInitializerContext = new ConnectionInitializerContext(connectionDescription, null); + var connectionInitializerContextAfterAuthentication = new ConnectionInitializerContext(connectionDescription, null); + + var mockConnectionInitializer = new Mock(); + mockConnectionInitializer + .Setup(i => i.SendHello(It.IsAny(), CancellationToken.None)) + .Returns(connectionInitializerContext); + mockConnectionInitializer + .Setup(i => i.Authenticate(It.IsAny(), It.IsAny(), CancellationToken.None)) + .Returns(connectionInitializerContextAfterAuthentication); + mockConnectionInitializer + .Setup(i => i.SendHelloAsync(It.IsAny(), CancellationToken.None)) + .ReturnsAsync(connectionInitializerContext); + mockConnectionInitializer + .Setup(i => i.AuthenticateAsync(It.IsAny(), It.IsAny(), CancellationToken.None)) + .ReturnsAsync(connectionInitializerContextAfterAuthentication); + + var subject = new BinaryConnection( + serverId: serverId, + endPoint: endPoint, + settings: new ConnectionSettings(), + streamFactory: mockStreamFactory.Object, + connectionInitializer: mockConnectionInitializer.Object, + eventSubscriber: capturedEvents, + LoggerFactory); + + if (async) + { + await subject.OpenAsync(CancellationToken.None); + } + else + { + subject.Open(CancellationToken.None); + } + + subject._state().Should().Be(3); // 3 - open. + } + } + + internal static class BinaryConnectionReflector + { + public static int _state(this BinaryConnection subject) + => ((InterlockedInt32)Reflector.GetFieldValue(subject, nameof(_state))).Value; + } +} From f2d2b106dd7821e426903e0fb86fa6d0c7e3342b Mon Sep 17 00:00:00 2001 From: Oleksandr Poliakov Date: Wed, 5 Mar 2025 11:08:43 -0800 Subject: [PATCH 2/2] PR --- .../mongodb-handshake/MongoDbHandshakeProseTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/MongoDB.Driver.Tests/Specifications/mongodb-handshake/MongoDbHandshakeProseTests.cs b/tests/MongoDB.Driver.Tests/Specifications/mongodb-handshake/MongoDbHandshakeProseTests.cs index 482a9d7b05f..8117f67bcc5 100644 --- a/tests/MongoDB.Driver.Tests/Specifications/mongodb-handshake/MongoDbHandshakeProseTests.cs +++ b/tests/MongoDB.Driver.Tests/Specifications/mongodb-handshake/MongoDbHandshakeProseTests.cs @@ -68,7 +68,7 @@ public async Task DriverAcceptsArbitraryAuthMechanism([Values(false, true)] bool .Setup(i => i.AuthenticateAsync(It.IsAny(), It.IsAny(), CancellationToken.None)) .ReturnsAsync(connectionInitializerContextAfterAuthentication); - var subject = new BinaryConnection( + using var subject = new BinaryConnection( serverId: serverId, endPoint: endPoint, settings: new ConnectionSettings(),