-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
CSHARP-4448: Implement OIDC SASL mechanism #1259
Conversation
@@ -140,5 +142,15 @@ private void AssertIsError(Exception actualException, bool expectedIsError) | |||
|
|||
actualException.Should().NotBeNull(); | |||
} | |||
|
|||
private static Exception UnwrapConnectionException(Exception ex) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have to add this, because unified tests trying to check the returned by server error code, but MongoDB C# driver wrap the original exception by MongoConnectionException in some particular cases.
src/MongoDB.Driver.Core/Core/Authentication/IAuthenticationContext.cs
Outdated
Show resolved
Hide resolved
|
||
public void ClearCache() | ||
{ | ||
_cachedCredentials = null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This might need synchronization. Or maybe even better, versioning.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
|
||
var response = _wrappedCallbackProvider.GetResponse(parameters, cancellationToken); | ||
credentials = new OidcCredentials(response.AccessToken, response.ExpiresIn, _clock); | ||
_cachedCredentials = credentials; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the following execution possible?
conn1/conn2 use same OidcCallbackAdapter
conn1/conn2 on Auth exception:
conn1: ClearCache
conn1: start GetCreds
conn1: _cachedCredentials = newCreds_conn1
conn2: ClearCache (_cachedCredentials == null)
conn1: finish GetCreds // _cachedCredentials == null
conn2: start GetCreds // _cachedCredentials == null
conn2: cachedCredentials = newCreds_conn2
newCreds_conn1 is now invalid (?), if so go to line: "conn1: ClearCache", which results in life-lock?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should not be a problem anymore, as code was improved to invalidate only own token.
src/MongoDB.Driver.Core/Core/Authentication/Oidc/OidcCallbackAdapter.cs
Outdated
Show resolved
Hide resolved
src/MongoDB.Driver.Core/Core/Authentication/Oidc/MongoOidcAuthenticator.cs
Outdated
Show resolved
Hide resolved
src/MongoDB.Driver.Core/Core/Authentication/Oidc/MongoOidcAuthenticator.cs
Outdated
Show resolved
Hide resolved
src/MongoDB.Driver.Core/Core/Authentication/Oidc/MongoOidcAuthenticator.cs
Outdated
Show resolved
Hide resolved
src/MongoDB.Driver.Core/Core/Authentication/Oidc/MongoOidcAuthenticator.cs
Outdated
Show resolved
Hide resolved
src/MongoDB.Driver.Core/Core/Authentication/Oidc/MongoOidcAuthenticator.cs
Outdated
Show resolved
Hide resolved
tests/MongoDB.Driver.Core.TestHelpers/Authentication/JwtHelper.cs
Outdated
Show resolved
Hide resolved
tests/MongoDB.Driver.Core.TestHelpers/Authentication/JwtHelper.cs
Outdated
Show resolved
Hide resolved
src/MongoDB.Driver.Core/Core/Authentication/IAuthenticatorFactory.cs
Outdated
Show resolved
Hide resolved
src/MongoDB.Driver.Core/Core/Authentication/Oidc/MongoOidcAuthenticator.cs
Outdated
Show resolved
Hide resolved
src/MongoDB.Driver.Core/Core/Authentication/Oidc/OidcConfiguration.cs
Outdated
Show resolved
Hide resolved
src/MongoDB.Driver.Core/Core/Authentication/Oidc/OidcConfiguration.cs
Outdated
Show resolved
Hide resolved
src/MongoDB.Driver.Core/Core/Authentication/SaslAuthenticator.cs
Outdated
Show resolved
Hide resolved
src/MongoDB.Driver.Core/Core/WireProtocol/CommandUsingCommandMessageWireProtocol.cs
Outdated
Show resolved
Hide resolved
src/MongoDB.Driver.Core/Core/WireProtocol/CommandUsingCommandMessageWireProtocol.cs
Outdated
Show resolved
Hide resolved
|
||
[Theory] | ||
[MemberData(nameof(ValidConfigurationTestCases))] | ||
public void Should_accept_valid_arguments(string principalName, IReadOnlyDictionary<string, object> mechanismProperties) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the convection is to have ctor_
in test name. We are testing the ctor afterall.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
|
||
[Theory] | ||
[MemberData(nameof(InvalidConfigurationTestCases))] | ||
public void Should_throw_on_invalid_arguments(string principalName, IReadOnlyDictionary<string, object> mechanismProperties) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider adding and validating string exceptionMessage
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added paramName validation.
@@ -338,7 +338,7 @@ public void Constructor_should_throw_an_ArgumentNullException_when_credential_is | |||
{ | |||
// We must call CustomizeInitialHelloCommand so that the authenticator thinks its started to speculatively | |||
// authenticate | |||
helloCommand = subject.CustomizeInitialHelloCommand(new BsonDocument { { OppressiveLanguageConstants.LegacyHelloCommandName, 1 } }); | |||
helloCommand = subject.CustomizeInitialHelloCommand(new BsonDocument { { OppressiveLanguageConstants.LegacyHelloCommandName, 1 } }, default); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe a good idea to have default value to cancelation token CancellationToken cancellationToken = default
like in rest of the API.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Other IAuthenticator members does not have default value for cancellationToken, would prefer to keep it as is for consistancy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Our authentication API is really an internal implementation detail. We can require CancellationToken
instances be specified IMHO.
@@ -37,7 +37,7 @@ public class ClusterBuilderTests | |||
public void CreateServerMonitorFactory_should_return_expected_result(int connectTimeoutMilliseconds, int heartbeatTimeoutMilliseconds, int expectedServerMonitorConnectTimeoutMilliseconds, int expectedServerMonitorSocketTimeoutMilliseconds) | |||
{ | |||
var connectTimeout = TimeSpan.FromMilliseconds(connectTimeoutMilliseconds); | |||
var authenticatorFactories = new[] { new AuthenticatorFactory(() => new DefaultAuthenticator(new UsernamePasswordCredential("source", "username", "password"), serverApi: null)) }; | |||
var authenticatorFactories = new[] { new AuthenticatorFactory(c => new DefaultAuthenticator(new UsernamePasswordCredential("source", "username", "password"), serverApi: null)) }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
minor: for unused param could just use _
, here and everywhere.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
tests/MongoDB.Driver.Core.Tests/Core/Configuration/ConnectionStringTests.cs
Show resolved
Hide resolved
var db = client.GetDatabase(DatabaseName); | ||
var collection = db.GetCollection<BsonDocument>(CollectionName); | ||
|
||
var tasks = Enumerable.Range(0, 10).Select(_ => Task.Run(async () => |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably need to use ThreadingUtilities.ExecuteOnNewThreads
for this.
Both for more deterministic testing, and for running actual 10 parallel threads.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
|
||
await Task.WhenAll(tasks); | ||
|
||
if (async) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could extract this to a helper method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
@@ -161,6 +162,11 @@ public static DisposableMongoClient CreateDisposableClient(Action<ClusterBuilder | |||
clientSettings.ServerApi = CoreTestConfiguration.ServerApi; | |||
clientSettingsConfigurator?.Invoke(clientSettings); | |||
|
|||
if (clientSettings.Credential.Mechanism == MongoOidcAuthenticator.MechanismName) | |||
{ | |||
OidcCallbackAdapterCachingFactory.Instance.Reset(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will collide with the future task of tests parallelization and creds caching tests. Not sure what's the best solution though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, we will. We have to provide a way to substitute the driver's components and replace the IOidcCallbackAdapterFactory in this case, so it will produce new Adapter for each of test. Probably ClientSettings could be nice point to host components.
var exception = Record.Exception(() => | ||
new OidcConfiguration(__endPoint, principalName, mechanismProperties, __buildInProvidersMock)); | ||
|
||
exception.Should().NotBeNull(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We probably need proper tests both for equality and cashingFactory.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
/// <param name="parameters">The information used by callbacks to authenticate with the Identity Provider.</param> | ||
/// <param name="cancellationToken">The cancellation token.</param> | ||
/// <returns>OIDC callback response</returns> | ||
OidcCallbackResponse GetOidcAccessToken(OidcCallbackParameters parameters, CancellationToken cancellationToken); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So do we want to return OidcAccessToken
, or still Response
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Renamed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking great. See inline feedback. Biggest question is whether we can acquire and cache auth tokens per cluster or if we must do it per endpoint. Right now the code implements per-endpoint.
src/MongoDB.Driver.Core/Core/Authentication/GssapiAuthenticator.cs
Outdated
Show resolved
Hide resolved
src/MongoDB.Driver.Core/Core/Authentication/Oidc/MongoOidcAuthenticator.cs
Outdated
Show resolved
Hide resolved
src/MongoDB.Driver.Core/Core/Authentication/Oidc/MongoOidcAuthenticator.cs
Outdated
Show resolved
Hide resolved
src/MongoDB.Driver.Core/Core/Authentication/IAuthenticationContext.cs
Outdated
Show resolved
Hide resolved
src/MongoDB.Driver.Core/Core/Connections/ConnectionInitializer.cs
Outdated
Show resolved
Hide resolved
src/MongoDB.Driver.Core/Core/Connections/ConnectionInitializer.cs
Outdated
Show resolved
Hide resolved
@@ -338,7 +338,7 @@ public void Constructor_should_throw_an_ArgumentNullException_when_credential_is | |||
{ | |||
// We must call CustomizeInitialHelloCommand so that the authenticator thinks its started to speculatively | |||
// authenticate | |||
helloCommand = subject.CustomizeInitialHelloCommand(new BsonDocument { { OppressiveLanguageConstants.LegacyHelloCommandName, 1 } }); | |||
helloCommand = subject.CustomizeInitialHelloCommand(new BsonDocument { { OppressiveLanguageConstants.LegacyHelloCommandName, 1 } }, default); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Our authentication API is really an internal implementation detail. We can require CancellationToken
instances be specified IMHO.
tests/MongoDB.Driver.Core.Tests/Core/Connections/BinaryConnectionTests.cs
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
src/MongoDB.Driver.Core/Core/Authentication/Oidc/OidcCallbackAdapter.cs
Outdated
Show resolved
Hide resolved
tests/MongoDB.Driver.Core.Tests/Core/Authentication/Oidc/OidcConfigurationTests.cs
Outdated
Show resolved
Hide resolved
src/MongoDB.Driver.Core/Core/Authentication/Oidc/OidcConfiguration.cs
Outdated
Show resolved
Hide resolved
return null; | ||
} | ||
|
||
return CreateNoTransitionClientLastSaslStep(cachedCredentials); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to update _usedCredentials
here as well?
If not, consider putting a comment explaining that. If yes, could just do it in CreateNoTransitionClientLastSaslStep
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are right. Added.
tests/MongoDB.Driver.Tests/Specifications/auth/AuthTestRunner.cs
Outdated
Show resolved
Hide resolved
tests/MongoDB.Driver.Tests/Specifications/auth/OidcAuthenticationProseTests.cs
Outdated
Show resolved
Hide resolved
tests/MongoDB.Driver.Tests/Specifications/auth/OidcAuthenticationProseTests.cs
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
49a229f
to
901d38f
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor rewording of error message but otherwise LGTM.
if (bytesReceivedFromServer?.Length > 0) | ||
{ | ||
// should not be reached | ||
throw new InvalidOperationException("Not all authentication response has been handled."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not all authentication response has been handled.
Received an additional {bytesReceivedFromServer} bytes from the server in last SASL response that was not expected.
@@ -80,7 +80,7 @@ | |||
}, | |||
{ | |||
"description": "should accept generic mechanism property (GSSAPI)", | |||
"uri": "mongodb://user%40DOMAIN.COM@localhost/?authMechanism=GSSAPI&authMechanismProperties=SERVICE_NAME:other,CANONICALIZE_HOST_NAME:true", | |||
"uri": "mongodb://user%40DOMAIN.COM@localhost/?authMechanism=GSSAPI&authMechanismProperties=SERVICE_NAME:other,CANONICALIZE_HOST_NAME:forward,SERVICE_HOST:example.com", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These changes are related to https://jira.mongodb.org/browse/CSHARP-3796, which we haven't implemented yet. Do the Kerberos (GSSAPI) forward
/forwardAndReverse
tests actually pass?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Discussed in Slack. MONGODB_URIs with CANONICALIZE_HOST_NAME
present are skipped.
6533419
to
63c8785
Compare
Current PR contains following changes: