Подключение MongoDB.Driver (.Net) с помощью SSL выдает значение не может быть нулевой ошибкой

#mongodb #mongodb-.net-driver

Вопрос:

Я пытаюсь подключить API .Net Core к моему защищенному SSL MongoDB. Я могу подключиться с помощью Mongo Compass, поэтому я уверен, что проблема не в моей конфигурации MongoDB.

Все работало нормально до того, как сертификаты были добавлены в MongoDB, и, как вы увидите, стек указывает прямо на сертификаты. Я просто не знаю, как это исправить.

Я не смог найти много документации о том, как реализовать SslSettings в драйвере MongoDB, поэтому я собираю это вместе из разных источников и поэтому задаю вопросы.

Проблема, похоже, возникает, когда мой API подключается к Mongo. Я получаю следующее исключение.

Значение не может быть равно нулю. (Параметр «источник»)

Дамп стека указывает прямо на то, что сертификаты X509 являются отсутствующим / нулевым значением.

 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, TValueamp; 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.APIEndpointsUsersUserService.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.lt;gt;c__DisplayClass1_0.lt;RealizeServicegt;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.lt;ExecuteAsyncgt;d__2.MoveNext() in C:Users...Demo.APIHostedServicesSubscriptionHostedService.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.lt;StartAsyncgt;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.lt;RunAsyncgt;d__4.MoveNext() at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.lt;RunAsyncgt;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.APIProgram.cs:line 22  

строка подключения appsettings.json

 mongodb://user:pass@localmongo:12345/MyDb?authSource=adminamp;readPreference=primaryamp;appname=demoapiamp;ssl=true  

AccessMongoClass.cs

 MongoCredential creds = MongoCredential.CreateMongoCRCredential("localmongo:12345", "user", "pass"); var clientCertificate = new Listlt;X509Certificategt;()  { 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) =gt; clientCertificate.ToList()[0],  ServerCertificateValidationCallback = (sender, certificate, chain, errors) =gt; true  };  MongoClient client = new MongoClient(settingz);  

На стороне mongodb я вижу эту ошибку:

 "ctx":"conn7","msg":"Interrupted operation as its client disconnected","attr":{"opId":1731}}  

Журнал Монго ОЧЕНЬ длинный, поэтому я просто выбираю то, что считаю ключевой строкой. Если вы хотите увидеть что-то еще, я могу легко добавить это.

Я бы подумал, что предоставил сертификаты X509, но, очевидно, мне чего-то не хватает.

Ответ №1:

Я предполагаю, что вы не увидите этого исключения, если просто создадите нового клиента и увидите полную ClusterRegistry.GetOrCreateCluster трассировку стека . Эта логика вызывается, когда драйвер пытается повторно использовать ранее созданный кластер, хранящийся в статическом хранилище( ClusterRegistry ). В вашем случае это выглядит так, как будто вы создаете 2 mongoClient с из настроек, подобных этому:

 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  

если это так, это ошибка в драйвере, постарайтесь не устанавливать значение null в ClientCertificates, например, вы можете назначить пустую коллекцию

Комментарии:

1. На самом деле я получаю ту же ошибку, просто используя строку подключения. Именно это побудило меня использовать более подробную попытку в операции с определением сертификатов x509. //Клиент MongoClient = новый(_mongoSettings. Строка подключения);

2. Я не думаю, что вы можете настроить сертификат x509 только с помощью строки подключения ,но ключевые моменты:1.при создании new MongoClient драйвер фактически пытается найти ранее созданные mongoClients, если он найден, то он пытается проверить, имеет ли найденный клиент те же настройки MongoClient, что и клиент, который вы собираетесь создать. 2. Для того он звонит MongoClientSettings.Equals , что по очереди звонит SslSettings.Equals , что по очереди звонит Equals X509CertificateCollection . И в этом методе есть ошибка, если право collection равно нулю, что приводит к ошибке, которую вы видите