4

I have following code to save to a local running mongo instance:

MongoCredential credential = MongoCredential.createCredential("myuser", "mydatabase", "mypassword".toCharArray());

MongoClient mongo = MongoClients.create(MongoClientSettings.builder()
                    .applyToClusterSettings(builder -> builder.hosts(Arrays.asList(new 
ServerAddress("localhost", 27017))))
                    .credential(credential)
                    .build());
MongoDatabase database = mongo.getDatabase("mydatabase");
MongoCollection<Document> collection = database.getCollection("mycollection");
collection.insertOne(document);

I have created a user for usernmae/password used in code above using db.createUser() command in mongo.exe shell and these are same credentials I provided while installing mongodb.

db.createUser(
{   user: "myuser",
    pwd: "mypassword",

    roles:[{role: "userAdminAnyDatabase" , db:"admin"}]})

But code fails with:

Exception in thread "main" com.mongodb.MongoSecurityException: Exception authenticating MongoCredential{mechanism=SCRAM-SHA-1, userName='myuser', source='mydatabase', password=<hidden>, mechanismProperties={}}

What am I missing here?

Mandroid
  • 6,200
  • 12
  • 64
  • 134

1 Answers1

9

Where, i.e. in which database did you create the user? Typically users are created in database admin. When you connect to a MongoDB then you should always specify the authentication database and the database you like to use.

The defaults are a bit confusing and not really consistent, esp. different drivers/tools seem to behave different. See this table to get an overview:

+-------------------------------------------------------------------------------------+
|Connection parameters                                    | Authentication | Current  |
|                                                         | database       | database |
+-------------------------------------------------------------------------------------+
|mongo -u user -p pwd --authenticationDatabase admin myDB |     admin      |   myDB   |
|mongo -u user -p pwd myDB                                |     myDB       |   myDB   |
|mongo -u user -p pwd --authenticationDatabase admin      |     admin      |   test   |
|mongo -u user -p pwd --host localhost:27017              |     admin      |   test   |
|mongo -u user -p pwd                                     |     admin      |   test   |
|mongo -u user -p pwd localhost:27017                     |     test       |   test   | 
|mongosh -u user -p pwd localhost:27017                   |     admin      |   test   | -> Different on mongosh and legacy mongo shell
+-------------------------------------------------------------------------------------+

If you like to use Connection string in URI format, it would correspond to these ones. There it is more consistent and well documented.

+-------------------------------------------------------------------------------------+
|Connection string                                        | Authentication | Current  |
|                                                         | database       | database |
+-------------------------------------------------------------------------------------+
|"mongodb://user:pwd@hostname/myDB?authSource=admin"      |     admin      |   myDB   |
|"mongodb://user:pwd@hostname/myDB"                       |     myDB       |   myDB   |
|"mongodb://user:pwd@hostname?authSource=admin"           |     admin      |   test   |
|"mongodb://user:pwd@hostname"                            |     admin      |   test   |
+-------------------------------------------------------------------------------------+

I guess you created the user in admin database but as you don't specify authenticationDatabase while connecting, Mongo defaults it to mydatabase where it fails, because user does not exist in database mydatabase.

Wernfried Domscheit
  • 54,457
  • 9
  • 76
  • 110
  • OK, so I think in MongoCredential credential = MongoCredential.createCredential("myuser", "mydatabase", "mypassword".toCharArray());..second argument must be the admin database as I used it for creating user. – Mandroid Sep 05 '20 at 15:21
  • Yes, should work. However, then you have to switch the database after connection is established. Typically you don't create any application collection in `admin` database. – Wernfried Domscheit Sep 05 '20 at 15:23
  • I havent created any collection in admin. But I did this change and it still throws authentication issue. – Mandroid Sep 05 '20 at 15:25
  • So now my code is as:MongoCredential credential = MongoCredential.createCredential("myuser", "admin", "mypassword".toCharArray()); But this too throws authentication error. – Mandroid Sep 05 '20 at 15:26
  • Connect with shell and use `db.getUsers()` to check in which DB the user is created. – Wernfried Domscheit Sep 05 '20 at 15:31
  • Its admin db, as shown in output of db.getUsers(). [ { "_id" : "test.myuser", "userId" : UUID("......"), "user" : "myuser", "db" : "test", "roles" : [ { "role" : "userAdminAnyDatabase", "db" : "admin" } ], "mechanisms" : [ "SCRAM-SHA-1", "SCRAM-SHA-256" ] } ] – Mandroid Sep 05 '20 at 15:34
  • 1
    No, the user-id is `test.myuser`, i.e. it is defined in `test` database. Run `use admin` before you create the user or run `db.getSiblingDB('admin').createUser(...)` You granted userAdminAnyDatabase on admin database, i.e. you permit the user to create users in admin database. However the user itself it created in test, thus you get authentication error when you try to authenticate in DB `admin` – Wernfried Domscheit Sep 05 '20 at 18:13
  • @WernfriedDomscheit the defaults behavior in the table you've posted, is this documented anywhere? I'm facing a similar issue using winston-mongodb, it throws an error starting up, about not having authority to execute on test db. – Anuja Sep 19 '21 at 21:19
  • Only generally. The documentation does not list all these cases individually. – Wernfried Domscheit Sep 20 '21 at 04:51