Search code examples
c#mongodbdockerasp.net-core-2.0mongodb-.net-driver

Unable to connect to MongoDb (using authentication) using mongocsharpdriver 2.7.0


I have created a sample c# console application to connect to mongodb hosted on CentOS machine on a docker.

The command used to create container is below:

docker run -d --name mongodb-container -p 2020:27017 -v /home/mongodb_data:/var/lib/mongodb/data -v /home/mongodb_log:/var/log/mongodb -v /home/mongod.conf:/etc/mongod.conf -e MONGO_INITDB_ROOT_USERNAME=mongoadmin -e MONGO_INITDB_ROOT_PASSWORD=secret mongo

System IP: 172.17.103.158
Mongodb docker port: 2020

Now coming to c# code

class users
    {
        [BsonId]
        public ObjectId _Id { get; set; }

        [BsonElement]
        public string name { get; set; }
    }

MongoContext Class

public class MongoContext
    {
        IMongoClient _client;
        public readonly IMongoDatabase _database;

        public MongoContext()
        {
            MongoCredential credential = MongoCredential.CreateCredential(ConfigurationManager.AppSettings["MongoDatabaseName"], ConfigurationManager.AppSettings["MongoUsername"], ConfigurationManager.AppSettings["MongoPassword"]);

            var settings = new MongoClientSettings
            {
                Credential = credential,
                VerifySslCertificate = false,
                ConnectionMode = ConnectionMode.ReplicaSet,
                ReplicaSetName = ConfigurationManager.AppSettings["MongoDatabaseName"],
                UseSsl = false,
                Server = new MongoServerAddress(ConfigurationManager.AppSettings["MongoHost"], Convert.ToInt32(ConfigurationManager.AppSettings["MongoPort"]))
            };

            _client = new MongoClient(settings);
            _database = _client.GetDatabase(ConfigurationManager.AppSettings["MongoDatabaseName"]);
        }
    }

Web Config:

<configuration>


<appSettings>
    <add key="MongoDatabaseName" value="clientdb" />
    <add key="MongoUsername" value="mongoadmin" />
    <add key="MongoPassword" value="secret" />
    <add key="MongoPort" value="2020" />
    <add key="MongoHost" value="172.17.103.158" />
  </appSettings>

</configuration>

Viewing Users

static List<users> ViewUsers()
    {
        try
        {
            MongoContext db = new MongoContext();
            IMongoCollection<users> Table1 = db._database.GetCollection<users>("users");

            return Table1.AsQueryable().ToList();
        }
        catch (Exception ex) { throw ex; }
    }

Error:

{"A timeout occured after 30000ms selecting a server using CompositeServerSelector{
  Selectors = MongoDB.Driver.MongoClient+AreSessionsSupportedServerSelector, LatencyLimitingServerSelector{
    AllowedLatencyRange = 00:00:00.0150000 } }.
Client view of cluster state is {
  ClusterId : \"1\",
  ConnectionMode : \"Automatic\",
  Type : \"Unknown\",
  State : \"Disconnected\",
  Servers : [{
    ServerId: \"{
      ClusterId : 1,
      EndPoint : \"172.17.103.158:2020\" }\",
    EndPoint: \"172.17.103.158:2020\",
    State: \"Disconnected\",
    Type: \"Unknown\",
    HeartbeatException: \"MongoDB.Driver.MongoConnectionException: An exception occurred while opening a connection to the server. 
        ---> MongoDB.Driver.MongoAuthenticationException: Unable to authenticate using sasl protocol mechanism SCRAM-SHA-1. 
        ---> MongoDB.Driver.MongoCommandException: Command saslStart failed: Authentication failed..\r\n   
      at MongoDB.Driver.Core.WireProtocol.CommandUsingQueryMessageWireProtocol`1.ProcessReply(ConnectionId connectionId, ReplyMessage`1 reply)\r\n   
      at MongoDB.Driver.Core.WireProtocol.CommandUsingQueryMessageWireProtocol`1.<ExecuteAsync>d__14.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   
      at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   
      at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   
      at MongoDB.Driver.Core.Authentication.SaslAuthenticator.<AuthenticateAsync>d__7.MoveNext()\r\n   --- End of inner exception stack trace ---\r\n   
      at MongoDB.Driver.Core.Authentication.SaslAuthenticator.<AuthenticateAsync>d__7.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   
      at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   
      at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   
      at MongoDB.Driver.Core.Authentication.DefaultAuthenticator.<AuthenticateAsync>d__7.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   
      at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   
      at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   
      at MongoDB.Driver.Core.Authentication.AuthenticationHelper.<AuthenticateAsync>d__1.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   
      at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   
      at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   
      at MongoDB.Driver.Core.Connections.ConnectionInitializer.<InitializeConnectionAsync>d__3.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   
      at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   
      at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   
      at MongoDB.Driver.Core.Connections.BinaryConnection.<OpenHelperAsync>d__48.MoveNext()\r\n   --- End of inner exception stack trace ---\r\n   
      at MongoDB.Driver.Core.Connections.BinaryConnection.<OpenHelperAsync>d__48.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   
      at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   
      at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   
      at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task)\r\n   
      at MongoDB.Driver.Core.Servers.ServerMonitor.<HeartbeatAsync>d__27.MoveNext()\" }] }."}

In Short Error Message:

{"A timeout occured after 30000ms selecting a server using CompositeServerSelector{
  Selectors = MongoDB.Driver.MongoClient+AreSessionsSupportedServerSelector, LatencyLimitingServerSelector{
    AllowedLatencyRange = 00:00:00.0150000 } }.
Client view of cluster state is {
  ClusterId : \"1\",
  ConnectionMode : \"Automatic\",
  Type : \"Unknown\",
  State : \"Disconnected\",
  Servers : [{
    ServerId: \"{
      ClusterId : 1,
      EndPoint : \"172.17.103.158:2020\" }\",
    EndPoint: \"172.17.103.158:2020\",
    State: \"Disconnected\",
    Type: \"Unknown\",
    HeartbeatException: \"MongoDB.Driver.MongoConnectionException: An exception occurred while opening a connection to the server. 
      ---> MongoDB.Driver.MongoAuthenticationException: Unable to authenticate using sasl protocol mechanism SCRAM-SHA-1. 
      ---> MongoDB.Driver.MongoCommandException: Command saslStart failed: Authentication failed..

I am facing this issue when mongo db is being protect by username and password otherwise not.

Altough MongoDb Compass is still able to connect to mongo db in both the cases.

My Question is : Why c# code is not getting connecting to mongodb when authentication is applied on db.

Solutions Tried:

  1. Connected using uri:

    mongodb://mongoadmin:secret@172.17.103.158:2020/clientdb
    
  2. Edited mongod.config => BindIp 127.0.0.1, 172.17.103.17 (My system IP)

  3. Using SCRAM-SHA-1 mechanism

Solution

  • Follow this link Mongo Site and look at Section

    The Database Component :
    The database component is optional and is used to indicate which database to authenticate against. When the database component is not provided, the “admin” database is used.

    The issue is you are authenticating the mongoadmin user for clientdb. But mongoadmin user is authenticated to admin db. Get the mongoadmin user authenticated and then you can access clientdb.

    Below is the sample using URI method:

            IMongoClient _client;
            public readonly IMongoDatabase _database;
    
            public MongoContext_URIBased()
            {
                var mongoUrl = new MongoUrl("mongodb://mongoadmin:secret@172.17.103.158:2020/admin");
                _client = new MongoClient(mongoUrl);
                _database = _client.GetDatabase("clientdb");
            } 
    

    And According to your code , below will work:

    Your config file should be like:

    <appSettings>
    <add key="MongoMasterDatabaseName" value="admin" />
    <add key="MongoUsername" value="mongoadmin" />
    <add key="MongoPassword" value="secret" />
    <add key="MongoPort" value="2020" />
    <add key="MongoHost" value="172.17.103.158" />
    <add key="MongoClientDatabaseName" value="clientDb" />
    
    
    </appSettings>
    

    And C# code :

    public class MongoContext
        {
            IMongoClient _client;
            public readonly IMongoDatabase _database;
    
            public MongoContext()
            {
                MongoCredential credential = MongoCredential.CreateCredential(ConfigurationManager.AppSettings["MongoMasterDatabaseName"], ConfigurationManager.AppSettings["MongoUsername"], ConfigurationManager.AppSettings["MongoPassword"]);
                var settings = new MongoClientSettings
                {
                    Credential = credential,
                    Server = new MongoServerAddress(, Convert.ToInt32(ConfigurationManager.AppSettings["MongoPort"]))
                };
                _client = new MongoClient(settings);
                _database = _client.GetDatabase(ConfigurationManager.AppSettings["MongoClientDatabaseName"]);
            }
        }
    

    As you can see, mongoadmin user is getting authenticated to admin db first. Then you can connect to clientdb