Unable to connect to MongoDB server using x509 certificate authentication from c# - mongodb

I have configured MongoDB server as given in document https://docs.mongodb.com/manual/core/security-x.509/
and I connected using mongo shell it is working fine.
Next I tried to connect to same server form c# driver, but Time out exception raised.
Below is my code
var cert = new X509Certificate2(#"C:\Program Files\MongoDB\Server\3.2\ssl\client.pfx", "secretkey");
var sslcrd = MongoCredential.CreateMongoX509Credential("CN=Client1,O=School,ST=Some-State,C=IN");
settings.SslSettings = new SslSettings() ;
settings.UseSsl = true;
settings.SslSettings.ClientCertificates = new List<X509Certificate>()
{
cert
};
settings.SslSettings.EnabledSslProtocols = SslProtocols.Default;
settings.SslSettings.ClientCertificateSelectionCallback =
(sender, host, certificates, certificate, issuers) => settings.SslSettings.ClientCertificates.ToList()[0];
settings.SslSettings.ServerCertificateValidationCallback = (sender, certificate, chain, errors) => true;
settings.SslSettings.CheckCertificateRevocation = false;
settings.VerifySslCertificate = false;
settings.Credentials = new[] { sslcrd };
MongoClient client = new MongoClient(settings);
var db = client.ListDatabases().ToList();
I went through MongoDB server logs and I am able to see below error
2017-04-10T11:18:21.559+0530 I NETWORK [initandlisten] connection
accepted from
127.0.0.1:53901 #64 (1 connection now open) 2017-04-10T11:18:21.559+0530 E NETWORK [conn64] no SSL certificate
provided by peer; connection rejected 2017-04-10T11:18:21.560+0530 I
NETWORK [conn64] end connection 127.0.0.1:53901 (0 connections now
open)
I am using c# MongoDB.Driver version 2.3.0
and MongoDB package is of version 3.2.
If you have solution for the above please do reply.

Set the value of allowConnectionsWithoutCertificates to false. Also, you need to combine the certificate and the key file.

In despite of this thread be a little bit old, I faced this exactly same issue today and found a solution at MongoDB.com site (Setup Connection Security code example), so,sharing the solution here for future searchs.
Basically the settings should be created from a connection string and follow the next steps straightforward:
using MongoDB.Bson;
using MongoDB.Driver;
using System;
using System.IO;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Security.Cryptography.X509Certificates;
class Program
{
static void Main(string[] args)
{
MainAsync().Wait();
}
static async Task MainAsync()
{
var connectionString = "mongodb+srv://<your-server.mongodb.net>/?authSource=%24external&authMechanism=MONGODB-X509&retryWrites=true&w=majority";
var settings = MongoClientSettings.FromConnectionString(connectionString);
settings.ServerApi = new ServerApi(ServerApiVersion.V1);
// You will need to convert your Atlas-provided PEM containing the cert/private keys into a PFX
// use openssl and the following line to create a PFX from your PEM:
// openssl pkcs12 -export -in <x509>.pem -inkey <x509>.pem -out <x509>.pfx
// and provide a password, which should match the second argument you pass to X509Certificate2
var cert = new X509Certificate2("<path_to_pfx>", "<pfx_passphrase>");
settings.SslSettings = new SslSettings
{
ClientCertificates = new List<X509Certificate>(){ cert }
};
var client = new MongoClient(settings);
var database = client.GetDatabase("testDB");
var collection = database.GetCollection<BsonDocument>("testCol");
var docCount = collection.CountDocuments("{}");
Console.WriteLine(docCount);
}
}

Related

Intermittent DB connection timeout in .NET 6 Console Application connecting to Azure SQL

We have a .Net Core Console Application accessing Azure SQL (Gen5, 4 vCores) deployed as a web job in Azure.
We recently upgraded our small console application to ef6(6.0.11)
Since quite some time, the application keeps throwing below exception intermittently for READ operations(highlighted in below code):
Microsoft.Data.SqlClient.SqlException (0x80131904): A connection was successfully established with the server, but then an error occurred during the pre-login handshake. (provider: SSL Provider, error: 0 - The wait operation timed out.)
We are clueless on Root Cause of this issue. Any hints on where to start looking # for root cause?
Any pointer would be highly appreciated.
NOTE : Connection string has following settings in azure
"ConnectionStrings": { "DBContext": "Server=Trusted_Connection=False;Encrypt=False;" }
Overall code looks something like below:
` var config = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.Build();
var builder = new SqlConnectionStringBuilder(config.GetConnectionString("DBContext"));
builder.Password = "";
builder.UserID = "";
builder.DataSource = "";
builder.InitialCatalog = "";
string _connection = builder.ConnectionString;
var sp = new ServiceCollection()
.AddDbContext<DBContext>(x => x.UseSqlServer(_connection, providerOptions => providerOptions.EnableRetryOnFailure()))
.BuildServiceProvider();
var db = sp.GetService<DBContext>();
lock(db)
{
var NewTriggers = db.Triggers.Where(x => x.IsSubmitted == false && x.Error == null).OrderBy(x => x.CreateOn).ToList();
}
`
We tried migrating from EF 3.1 to EF 6.0.11. We were expecting a smooth transition

Flutter Dio Networking: SSL pinning using certificate's public hashed key string (not a file)

I currently use the following snippet to include my SSL certificate file into the http client:
final List<int>? _certBytes; //I read it from .cer file included in the project
(_dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate =
(client) {
if (_certBytes != null) {
SecurityContext sc = SecurityContext();
sc.setTrustedCertificatesBytes(_certBytes!);
HttpClient httpClient = HttpClient(context: sc);
return httpClient;
} else {
client.badCertificateCallback =
((X509Certificate cert, String host, int port) => true);
return client;
}
};
while this code works well, it will stop working if the certificate is expired, which means that I need to add a new certificate file into the app and upload again to the app stores, so I decided to host the certificate as a hashed string in Firebase's Remote Config and read it upon app launch, so I can change the certificate remotely without building new versions for the app, but couldn't find a way to set the SecurityContext with a certificate hashed string in the Dio's HTTPClient

Spring boot mongo tls cert

I have set up TLS in mongod.conf. I need to use spring boot to connect to my mongo which requires tls now. In MongoCompass, I set Certificate Authority, Client Certificate & Client Private Key to root-ca.pem, test.pem & test.pem accordingly and I am able to connect. How can i specify the root-ca.pem & test.pem correctly in mongoclientoptions to connect to my mongo?
This is my mongod.conf
# network interfaces
net:
port: 27017
bindIp: 127.0.0.1
tls:
mode: requireTLS
certificateKeyFile: C:\TLSServerMongo\test.pem
CAFile: C:\TLSServerMongo\root-ca.pem
clusterFile: C:\TLSServerMongo\test.pem
allowInvalidCertificates: true
FIPSMode : false
This is my mongoclientoptions
#Bean
public MongoClientOptions mongoClientOptions() {
MongoClientOptions.Builder mongoClientOptions = MongoClientOptions.builder().sslInvalidHostNameAllowed(true).sslEnabled(true);
try {
// String fileName = directory + RDS_COMBINED_CA_BUNDLE;
String fileName = "C:\\TLSServerMongo\\test.pem";
InputStream is = new FileInputStream(fileName);
// You could get a resource as a stream instead.
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate caCert = (X509Certificate) cf.generateCertificate(is);
TrustManagerFactory tmf = TrustManagerFactory
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(null); // You don't need the KeyStore instance to come from a file.
ks.setCertificateEntry("caCert", caCert);
tmf.init(ks);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), null);
mongoClientOptions.sslContext(sslContext);
} catch (Exception e) {
LOGGER.error(e.getMessage());
}
return mongoClientOptions.build();
}
This is my MongoClient
public #Bean
MongoClient mongoClient() {
List<MongoCredential> allCred = new ArrayList<>();
allCred.add(MongoCredential.createCredential(username, database, password.toCharArray()));
MongoClient client = new MongoClient((new ServerAddress(this.myHost, this.myPort)), allCred, mongoClientOptions());
client.setWriteConcern(WriteConcern.ACKNOWLEDGED);
return client;
}
It will be a Good idea to create one single .jks file as a cert and use it in spring boot mongo client...
pls refre to this for converting your .pem cert into JKS Convert .pem files to .jks
Once you have the .jks in your keystore on your system then we can use it or you may follow this example to connect using jks...
Connecting to MongoDB from spring boot app using ssl
or
https://dba.stackexchange.com/questions/206462/how-to-configure-ssl-mongodb-connection-in-yml-file-spring-boot
Hope it helps!

How do I use the ComponentSpace library to programmatically update cached X509 certificate files when I update SAMLController.Configurations

Good day All,
I am using ComponentSpace as a Service Provider to establish SAML2 Single Sign On to my for my clients. The clients use their own identity providers to authenticate and gain access to my MVC5 web application. The issue I am having is that when a client wants to update their X509 certificate files I update the physical files dynamically, but I have to do an IIS reset to get the new certificate files to be used. How can I avoid having to do an IIS reset and get ComponentSpace to use the new X509 certificate files when authenticating. An example of my code is below.
var samlConfiguration = new
ComponentSpace.SAML2.Configuration.SAMLConfiguration();
var ssoUrl = "https://www.ssoUrl/Consumer";
var ssoName ="https://www.ssoName";
var localServiceProviderConfiguration = new LocalServiceProviderConfiguration()
{
Name = ssoName,
AssertionConsumerServiceUrl = ssoUrl
};
samlConfiguration.LocalServiceProviderConfiguration = localServiceProviderConfiguration ;
var certNamePrimary = ConfigurationManager.AppSettings["Certificate_Path"] + "cert-A.cer";
var certNameSecondary = ConfigurationManager.AppSettings["Certificate_Path"] + "cert-B.cer";
var partnerIdentityProviderConfiguration = new
ComponentSpace.SAML2.Configuration.PartnerIdentityProviderConfiguration()
{
Name = clientConfig.PartnerIdPName,
SingleSignOnServiceUrl = clientConfig.IdPSingleSignOnServiceURL,
SignAuthnRequest = false,
WantSAMLResponseSigned = false,
WantAssertionEncrypted = false,
WantAssertionSigned = true,
PartnerCertificateFile = certNamePrimary ,
SecondaryPartnerCertificateFile = certNameSecondary
};
samlConfiguration.PartnerIdentityProviderConfigurations.AddPartnerIdentityProvider(partnerIdentityProviderConfiguration );
if (ComponentSpace.SAML2.SAMLController.Configurations.Keys.Contains(ssoUrl))
{
ComponentSpace.SAML2.SAMLController.Configurations.Remove(ssoUrl);
ComponentSpace.SAML2.SAMLController.Configurations.Add(ssoUrl, samlConfiguration);
}
else
ComponentSpace.SAML2.SAMLController.Configurations.Add(ssoUrl, samlConfiguration);
ComponentSpace.SAML2.SAMLController.ConfigurationID = ssoUrl;
SAMLServiceProvider.InitiateSSO(Response, null, "http://company.com/adfs/services/trust");

How to create a truststore.jks with one certificate?

(I'm a newby in cryptographic things.)
I have an setup program written in C#. This asks the user to input the server URL. Then it connects to this server and stores this server certificate into a truststore file that is used by the installed Java REST service.
The truststore file is created by keytool.exe:
keytool.exe -alias anAlias -import -file cert.cer -noprompt -keystore truststore.jks -storepass aPassword
Now we don't want to use keytool.exe. We want to create the keystore by C#. My first tries are as follows:
class AddCertToTruststore
{
public static void Do()
{
ServicePointManager.ServerCertificateValidationCallback += Validate;
X509Certificate2 cert = new X509Certificate2("cert.cer");
cert.Archived = true;
bool ok = cert.Verify(); // always false
X509Certificate2Collection certs = new X509Certificate2Collection();
certs.Add(cert);
byte[] bytes = certs.Export(X509ContentType.Pkcs12);
File.WriteAllBytes("truststore.jks", bytes);
ServicePointManager.ServerCertificateValidationCallback -= Validate;
}
private static bool Validate(object sender, X509Certificate certificate, X509Chain chain,
SslPolicyErrors sslPolicyErrors)
{
return true;
}
}
This code creates a truststore but I'm missing the certificate in it. If I open the truststore.jks with KeyStore Explorer 5.1 there is not any certificate in it. What am I doing wrong?
The certificate is a self-signed certificate. cert.Verify() returns always false.
It's just one line that is missing:
cert.FriendlyName = "anAlias";
It works also without the validation handler and without setting Archived property. So the shortest code is:
X509Certificate2 cert = new X509Certificate2(#"cert.cer");
cert.FriendlyName = "anAlias";
X509Certificate2Collection certs = new X509Certificate2Collection();
certs.Add(cert);
byte[] bytes = certs.Export(X509ContentType.Pkcs12);
File.WriteAllBytes(#"truststore.jks", bytes);