Skip to content

CSHARP-3538: CSOT: Auth #1720

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 19 additions & 20 deletions src/MongoDB.Driver/Authentication/AuthenticationHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Cryptography;
using System.Threading;
using System.Threading.Tasks;
using MongoDB.Bson;
using MongoDB.Bson.IO;
Expand All @@ -28,8 +27,9 @@ namespace MongoDB.Driver.Authentication
{
internal static class AuthenticationHelper
{
public static void Authenticate(IConnection connection, ConnectionDescription description, IAuthenticator authenticator, CancellationToken cancellationToken)
public static void Authenticate(OperationContext operationContext, IConnection connection, ConnectionDescription description, IAuthenticator authenticator)
{
Ensure.IsNotNull(operationContext, nameof(operationContext));
Ensure.IsNotNull(connection, nameof(connection));
Ensure.IsNotNull(description, nameof(description));

Expand All @@ -41,12 +41,13 @@ public static void Authenticate(IConnection connection, ConnectionDescription de
// authentication is currently broken on arbiters
if (!description.HelloResult.IsArbiter)
{
authenticator.Authenticate(connection, description, cancellationToken);
authenticator.Authenticate(operationContext, connection, description);
}
}

public static async Task AuthenticateAsync(IConnection connection, ConnectionDescription description, IAuthenticator authenticator, CancellationToken cancellationToken)
public static async Task AuthenticateAsync(OperationContext operationContext, IConnection connection, ConnectionDescription description, IAuthenticator authenticator)
{
Ensure.IsNotNull(operationContext, nameof(operationContext));
Ensure.IsNotNull(connection, nameof(connection));
Ensure.IsNotNull(description, nameof(description));

Expand All @@ -58,7 +59,7 @@ public static async Task AuthenticateAsync(IConnection connection, ConnectionDes
// authentication is currently broken on arbiters
if (!description.HelloResult.IsArbiter)
{
await authenticator.AuthenticateAsync(connection, description, cancellationToken).ConfigureAwait(false);
await authenticator.AuthenticateAsync(operationContext, connection, description).ConfigureAwait(false);
}
}

Expand All @@ -68,30 +69,28 @@ public static string MongoPasswordDigest(string username, SecureString password)
{
return MongoPasswordDigest(username, new byte[0]);
}
else

var passwordIntPtr = Marshal.SecureStringToGlobalAllocUnicode(password);
try
{
var passwordIntPtr = Marshal.SecureStringToGlobalAllocUnicode(password);
var passwordChars = new char[password.Length];
var passwordCharsHandle = GCHandle.Alloc(passwordChars, GCHandleType.Pinned);
try
{
var passwordChars = new char[password.Length];
var passwordCharsHandle = GCHandle.Alloc(passwordChars, GCHandleType.Pinned);
try
{
Marshal.Copy(passwordIntPtr, passwordChars, 0, password.Length);
Marshal.Copy(passwordIntPtr, passwordChars, 0, password.Length);

return MongoPasswordDigest(username, passwordChars);
}
finally
{
Array.Clear(passwordChars, 0, passwordChars.Length);
passwordCharsHandle.Free();
}
return MongoPasswordDigest(username, passwordChars);
}
finally
{
Marshal.ZeroFreeGlobalAllocUnicode(passwordIntPtr);
Array.Clear(passwordChars, 0, passwordChars.Length);
passwordCharsHandle.Free();
}
}
finally
{
Marshal.ZeroFreeGlobalAllocUnicode(passwordIntPtr);
}
}

private static string MongoPasswordDigest(string username, char[] passwordChars)
Expand Down
21 changes: 10 additions & 11 deletions src/MongoDB.Driver/Authentication/DefaultAuthenticator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using MongoDB.Bson;
using MongoDB.Driver.Authentication.ScramSha;
Expand Down Expand Up @@ -54,7 +53,7 @@ internal DefaultAuthenticator(

public string Name => "DEFAULT";

public void Authenticate(IConnection connection, ConnectionDescription description, CancellationToken cancellationToken)
public void Authenticate(OperationContext operationContext, IConnection connection, ConnectionDescription description)
{
Ensure.IsNotNull(connection, nameof(connection));
Ensure.IsNotNull(description, nameof(description));
Expand All @@ -65,20 +64,20 @@ public void Authenticate(IConnection connection, ConnectionDescription descripti
if (!description.HelloResult.HasSaslSupportedMechs
&& Feature.ScramSha256Authentication.IsSupported(description.MaxWireVersion))
{
var command = CustomizeInitialHelloCommand(HelloHelper.CreateCommand(_serverApi, loadBalanced: connection.Settings.LoadBalanced), cancellationToken);
var command = CustomizeInitialHelloCommand(operationContext, HelloHelper.CreateCommand(_serverApi, loadBalanced: connection.Settings.LoadBalanced));
var helloProtocol = HelloHelper.CreateProtocol(command, _serverApi);
var helloResult = HelloHelper.GetResult(connection, helloProtocol, cancellationToken);
var helloResult = HelloHelper.GetResult(operationContext, connection, helloProtocol);
var mergedHelloResult = new HelloResult(description.HelloResult.Wrapped.Merge(helloResult.Wrapped));
description = new ConnectionDescription(
description.ConnectionId,
mergedHelloResult);
}

var authenticator = GetOrCreateAuthenticator(connection, description);
authenticator.Authenticate(connection, description, cancellationToken);
authenticator.Authenticate(operationContext, connection, description);
}

public async Task AuthenticateAsync(IConnection connection, ConnectionDescription description, CancellationToken cancellationToken)
public async Task AuthenticateAsync(OperationContext operationContext, IConnection connection, ConnectionDescription description)
{
Ensure.IsNotNull(connection, nameof(connection));
Ensure.IsNotNull(description, nameof(description));
Expand All @@ -89,20 +88,20 @@ public async Task AuthenticateAsync(IConnection connection, ConnectionDescriptio
if (!description.HelloResult.HasSaslSupportedMechs
&& Feature.ScramSha256Authentication.IsSupported(description.MaxWireVersion))
{
var command = CustomizeInitialHelloCommand(HelloHelper.CreateCommand(_serverApi, loadBalanced: connection.Settings.LoadBalanced), cancellationToken);
var command = CustomizeInitialHelloCommand(operationContext, HelloHelper.CreateCommand(_serverApi, loadBalanced: connection.Settings.LoadBalanced));
var helloProtocol = HelloHelper.CreateProtocol(command, _serverApi);
var helloResult = await HelloHelper.GetResultAsync(connection, helloProtocol, cancellationToken).ConfigureAwait(false);
var helloResult = await HelloHelper.GetResultAsync(operationContext, connection, helloProtocol).ConfigureAwait(false);
var mergedHelloResult = new HelloResult(description.HelloResult.Wrapped.Merge(helloResult.Wrapped));
description = new ConnectionDescription(
description.ConnectionId,
mergedHelloResult);
}

var authenticator = GetOrCreateAuthenticator(connection, description);
await authenticator.AuthenticateAsync(connection, description, cancellationToken).ConfigureAwait(false);
await authenticator.AuthenticateAsync(operationContext, connection, description).ConfigureAwait(false);
}

public BsonDocument CustomizeInitialHelloCommand(BsonDocument helloCommand, CancellationToken cancellationToken)
public BsonDocument CustomizeInitialHelloCommand(OperationContext operationContext, BsonDocument helloCommand)
{
var saslSupportedMechs = CreateSaslSupportedMechsRequest(_identity);
helloCommand = helloCommand.Merge(saslSupportedMechs);
Expand All @@ -116,7 +115,7 @@ public BsonDocument CustomizeInitialHelloCommand(BsonDocument helloCommand, Canc
out var authenticator))
{
_speculativeAuthenticator = authenticator;
return _speculativeAuthenticator.CustomizeInitialHelloCommand(helloCommand, cancellationToken);
return _speculativeAuthenticator.CustomizeInitialHelloCommand(operationContext, helloCommand);
}

return helloCommand;
Expand Down
7 changes: 3 additions & 4 deletions src/MongoDB.Driver/Authentication/IAuthenticator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
* limitations under the License.
*/

using System.Threading;
using System.Threading.Tasks;
using MongoDB.Bson;
using MongoDB.Driver.Core.Connections;
Expand All @@ -24,10 +23,10 @@ internal interface IAuthenticator
{
string Name { get; }

void Authenticate(IConnection connection, ConnectionDescription description, CancellationToken cancellationToken);
void Authenticate(OperationContext operationContext, IConnection connection, ConnectionDescription description);

Task AuthenticateAsync(IConnection connection, ConnectionDescription description, CancellationToken cancellationToken);
Task AuthenticateAsync(OperationContext operationContext, IConnection connection, ConnectionDescription description);

BsonDocument CustomizeInitialHelloCommand(BsonDocument helloCommand, CancellationToken cancellationToken);
BsonDocument CustomizeInitialHelloCommand(OperationContext operationContext, BsonDocument helloCommand);
}
}
13 changes: 5 additions & 8 deletions src/MongoDB.Driver/Authentication/MongoDBX509Authenticator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
*/

using System;
using System.Threading;
using System.Threading.Tasks;
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Serializers;
Expand Down Expand Up @@ -45,7 +44,7 @@ public string Name
get { return MechanismName; }
}

public void Authenticate(IConnection connection, ConnectionDescription description, CancellationToken cancellationToken)
public void Authenticate(OperationContext operationContext, IConnection connection, ConnectionDescription description)
{
Ensure.IsNotNull(connection, nameof(connection));
Ensure.IsNotNull(description, nameof(description));
Expand All @@ -58,16 +57,15 @@ public void Authenticate(IConnection connection, ConnectionDescription descripti
try
{
var protocol = CreateAuthenticateProtocol();
// TODO: CSOT: implement operationContext support for Auth.
protocol.Execute(new OperationContext(Timeout.InfiniteTimeSpan, cancellationToken), connection);
protocol.Execute(operationContext, connection);
}
catch (MongoCommandException ex)
{
throw CreateException(connection, ex);
}
}

public async Task AuthenticateAsync(IConnection connection, ConnectionDescription description, CancellationToken cancellationToken)
public async Task AuthenticateAsync(OperationContext operationContext, IConnection connection, ConnectionDescription description)
{
Ensure.IsNotNull(connection, nameof(connection));
Ensure.IsNotNull(description, nameof(description));
Expand All @@ -80,16 +78,15 @@ public async Task AuthenticateAsync(IConnection connection, ConnectionDescriptio
try
{
var protocol = CreateAuthenticateProtocol();
// TODO: CSOT: implement operationContext support for Auth.
await protocol.ExecuteAsync(new OperationContext(Timeout.InfiniteTimeSpan, cancellationToken), connection).ConfigureAwait(false);
await protocol.ExecuteAsync(operationContext, connection).ConfigureAwait(false);
}
catch (MongoCommandException ex)
{
throw CreateException(connection, ex);
}
}

public BsonDocument CustomizeInitialHelloCommand(BsonDocument helloCommand, CancellationToken cancellationToken)
public BsonDocument CustomizeInitialHelloCommand(OperationContext operationContext, BsonDocument helloCommand)
{
helloCommand.Add("speculativeAuthenticate", CreateAuthenticateCommand());
return helloCommand;
Expand Down
25 changes: 14 additions & 11 deletions src/MongoDB.Driver/Authentication/SaslAuthenticator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
using System;
using System.Collections.Generic;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Serializers;
Expand Down Expand Up @@ -72,7 +71,7 @@ internal SaslAuthenticator(ISaslMechanism mechanism, ServerApi serverApi)

public string Name => Mechanism.Name;

public void Authenticate(IConnection connection, ConnectionDescription description, CancellationToken cancellationToken)
public void Authenticate(OperationContext operationContext, IConnection connection, ConnectionDescription description)
{
Ensure.IsNotNull(connection, nameof(connection));
Ensure.IsNotNull(description, nameof(description));
Expand All @@ -91,7 +90,9 @@ public void Authenticate(IConnection connection, ConnectionDescription descripti

while (currentStep != null)
{
var executionResult = currentStep.Execute(conversation, result?["payload"]?.AsByteArray, cancellationToken);
#pragma warning disable CS0618 // Type or member is obsolete
var executionResult = currentStep.Execute(conversation, result?["payload"]?.AsByteArray, operationContext.CombinedCancellationToken);
#pragma warning restore CS0618 // Type or member is obsolete
if (executionResult.BytesToSendToServer == null)
{
currentStep = executionResult.NextStep;
Expand All @@ -109,8 +110,7 @@ public void Authenticate(IConnection connection, ConnectionDescription descripti
try
{
var protocol = CreateCommandProtocol(command);
// TODO: CSOT: implement operationContext support for Auth.
result = protocol.Execute(new OperationContext(Timeout.InfiniteTimeSpan, cancellationToken), connection);
result = protocol.Execute(operationContext, connection);
conversationId ??= result?.GetValue("conversationId").AsInt32;
}
catch (MongoException ex)
Expand All @@ -136,7 +136,7 @@ public void Authenticate(IConnection connection, ConnectionDescription descripti
}
}

public async Task AuthenticateAsync(IConnection connection, ConnectionDescription description, CancellationToken cancellationToken)
public async Task AuthenticateAsync(OperationContext operationContext, IConnection connection, ConnectionDescription description)
{
Ensure.IsNotNull(connection, nameof(connection));
Ensure.IsNotNull(description, nameof(description));
Expand All @@ -155,7 +155,9 @@ public async Task AuthenticateAsync(IConnection connection, ConnectionDescriptio

while (currentStep != null)
{
var executionResult = await currentStep.ExecuteAsync(conversation, result?["payload"]?.AsByteArray, cancellationToken).ConfigureAwait(false);
#pragma warning disable CS0618 // Type or member is obsolete
var executionResult = await currentStep.ExecuteAsync(conversation, result?["payload"]?.AsByteArray, operationContext.CombinedCancellationToken).ConfigureAwait(false);
#pragma warning restore CS0618 // Type or member is obsolete
if (executionResult.BytesToSendToServer == null)
{
currentStep = executionResult.NextStep;
Expand All @@ -173,8 +175,7 @@ public async Task AuthenticateAsync(IConnection connection, ConnectionDescriptio
try
{
var protocol = CreateCommandProtocol(command);
// TODO: CSOT: implement operationContext support for Auth.
result = await protocol.ExecuteAsync(new OperationContext(Timeout.InfiniteTimeSpan, cancellationToken), connection).ConfigureAwait(false);
result = await protocol.ExecuteAsync(operationContext, connection).ConfigureAwait(false);
conversationId ??= result?.GetValue("conversationId").AsInt32;
}
catch (MongoException ex)
Expand All @@ -200,12 +201,14 @@ public async Task AuthenticateAsync(IConnection connection, ConnectionDescriptio
}
}

public BsonDocument CustomizeInitialHelloCommand(BsonDocument helloCommand, CancellationToken cancellationToken)
public BsonDocument CustomizeInitialHelloCommand(OperationContext operationContext, BsonDocument helloCommand)
{
var speculativeStep = Mechanism.CreateSpeculativeAuthenticationStep();
if (speculativeStep != null)
{
(var bytesToSend, _speculativeContinueStep) = speculativeStep.Execute(null, null, cancellationToken);
#pragma warning disable CS0618 // Type or member is obsolete
(var bytesToSend, _speculativeContinueStep) = speculativeStep.Execute(null, null, operationContext.CombinedCancellationToken);
#pragma warning restore CS0618 // Type or member is obsolete
var firstCommand = CreateStartCommand(bytesToSend);
firstCommand.Add("db", Mechanism.DatabaseName);
helloCommand.Add("speculativeAuthenticate", firstCommand);
Expand Down
Loading