Reputation: 5619
I'm trying to connect a .Net Core API to my SSL protected MongoDB. I can connect using Mongo Compass so I am confident the problem is not in my MongoDB configuration.
Everything was working fine before the certificates were added to the MongoDB and as you'll see the stack points right to the certificates. I just don't know how to correct it.
I wasn't able to find a lot of documentation on how to implement the SslSettings in the MongoDB driver so I'm piecing this together from different sources and SO questions.
The problem seems to come when my API goes to connect to Mongo. I get the following exception.
Value cannot be null. (Parameter 'source')
The stack dump points right to the X509 certificates being the missing / null value.
at System.Linq.ThrowHelper.ThrowArgumentNullException(ExceptionArgument argument)
at System.Linq.Enumerable.Cast[TResult](IEnumerable source)
at MongoDB.Driver.SslSettings.X509CertificateCollectionEqualityComparer.Equals(X509CertificateCollection lhs, X509CertificateCollection rhs)
at MongoDB.Driver.SslSettings.Equals(Object obj)
at System.Object.Equals(Object objA, Object objB)
at MongoDB.Driver.ClusterKey.Equals(Object obj)
at System.Collections.Generic.ObjectEqualityComparer`1.Equals(T x, T y)
at System.Collections.Generic.Dictionary`2.FindValue(TKey key)
at System.Collections.Generic.Dictionary`2.TryGetValue(TKey key, TValue& value)
at MongoDB.Driver.ClusterRegistry.GetOrCreateCluster(ClusterKey clusterKey)
at MongoDB.Driver.MongoClient..ctor(MongoClientSettings settings)
at MongoDB.Driver.MongoClient..ctor(String connectionString)
at Bullies.API.Endpoints.Users.UserService..ctor(IOptions`1 config, IMediator mediator) in C:\Users\...\Demo.API\Endpoints\Users\UserService.cs:line 38
at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor, Boolean wrapExceptions)
at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine.<>c__DisplayClass1_0.<RealizeService>b__0(ServiceProviderEngineScope scope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
at Demo.API.HostedServices.SubscriptionHostedService.<ExecuteAsync>d__2.MoveNext() in C:\Users\...\Demo.API\HostedServices\SubscriptionHostedService.cs:line 32
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.ConfiguredTaskAwaitable.ConfiguredTaskAwaiter.GetResult()
at Microsoft.Extensions.Hosting.Internal.Host.<StartAsync>d__9.MoveNext()
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.ConfiguredTaskAwaitable.ConfiguredTaskAwaiter.GetResult()
at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.<RunAsync>d__4.MoveNext()
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.<RunAsync>d__4.MoveNext()
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.Run(IHost host)
at Demo.API.Program.Main(String[] args) in C:\...\Demo.API\Program.cs:line 22
appsettings.json connection string
mongodb://user:pass@localmongo:12345/MyDb?authSource=admin&readPreference=primary&appname=demoapi&ssl=true
AccessMongoClass.cs
MongoCredential creds = MongoCredential.CreateMongoCRCredential("localmongo:12345", "user", "pass");
var clientCertificate = new List<X509Certificate>()
{ new X509Certificate("Path\\...\\mysite_com.pfx", "privateKeyPassword") };
MongoClientSettings settingz = new MongoClientSettings();
settingz.ApplicationName = "demo-api";
settingz.Credential = creds;
settingz.SslSettings = new SslSettings()
{
CheckCertificateRevocation = false,
//EnabledSslProtocols = System.Security.Authentication.SslProtocols.Tls12,
ClientCertificates = clientCertificate,
ClientCertificateSelectionCallback =
(sender, host, certificates, certificate, issuers) => clientCertificate.ToList()[0],
ServerCertificateValidationCallback = (sender, certificate, chain, errors) => true
};
MongoClient client = new MongoClient(settingz);
On the mongodb side I see this error:
"ctx":"conn7","msg":"Interrupted operation as its client disconnected","attr":{"opId":1731}}
The Mongo log is VERY long so I'm just picking out what I think is the key line. If you want to see something else I can easily add it.
I would have thought I provided the X509 certificates but clearly I'm missing something.
Upvotes: 0
Views: 1228
Reputation: 4897
I assume you don't see this exception if you just create a new client and in the full stacktrace you see ClusterRegistry.GetOrCreateCluster
. This logic is called when the driver is trying to reuse previously created cluster that is stored in a static storage(ClusterRegistry
). In your case it looks like you create 2 mongoClient
s from the settings like this:
var clientSettings1 = new MongoClientSettings()
{
SslSettings = new SslSettings
{
ClientCertificates = new X509Certificate2[] { new X509Certificate2(@"path", "pass") }
}
};
// create client 1
var clientSettings2 = new MongoClientSettings()
{
SslSettings = new SslSettings
{
ClientCertificates = null
}
};
// create client 2
if so, it's a bug in the driver, try avoid setting a null in ClientCertificates for example you can assign an empty collection
Upvotes: 1