Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to solve 'command find requires authentication' using Node.js and mongoose?

I need help to fix the error. My ubuntu server 16.04 running:

MongoDB shell version v4.0.9

Node 11.6

mongoose 5.3.4

When the security on /etc/mongod.conf is:

security: authorization: "disabled" I can use :

const mongoURI = 'mongodb://writeApp:[email protected]:27017/writeapp';

const db = mongoose.connect(mongoURI, { useNewUrlParser: true });

All database commands work. Even I checked by putting wrong password, It shows auth fail. But as you know mongodb will still work as authorization is disabled.

My user data is correct as checked by db.getUsers() from command line:

> db.getUsers();
[
 {
    "_id" : "admin.root",
    "userId" : UUID("8f6c1295-a261-4057-9a29-8a9919437841"),
    "user" : "root",
    "db" : "admin",
    "roles" : [
        {
            "role" : "userAdminAnyDatabase",
            "db" : "admin"
        }
    ],
    "mechanisms" : [
        "SCRAM-SHA-1",
        "SCRAM-SHA-256"
    ]
 },
 {
    "_id" : "admin.writeApp",
    "userId" : UUID("ee148506-1860-4739-80db-17352e0e2ccb"),
    "user" : "writeApp",
    "db" : "admin",
    "roles" : [
        {
            "role" : "dbOwner",
            "db" : "writeapp"
        },
        {
            "role" : "listDatabases",
            "db" : "admin"
        }
    ],
    "mechanisms" : [
        "SCRAM-SHA-1",
        "SCRAM-SHA-256"
    ]
  }
]

The real problem: so I nano /etc/mongod.conf and changed the authorization:"enabled" after that restarted mongo. When I re run my app, following error occurs:

{ MongoError: command find requires authentication
 ............
 ............
 ok: 0,
 errmsg: 'command find requires authentication',
code: 13,
codeName: 'Unauthorized',
name: 'MongoError',
[Symbol(mongoErrorContextSymbol)]: {} }

After spending long time, I connected using mongo shell:

mongo -u "writeApp" -p writeApp9779 --authenticationDatabase "admin"
> use writeapp;
  switched to db writeapp
> db.users.find();
  { "_id" : ObjectId("5cb63f23755c4469f8f6e2e6"),
  ..........
  }

It is working in the console but not in the application.I can't find any solution. Really need your kind consideration. By the way here is a sample node.js

Category.find(function(err, categories){
if(err) console.log(err);
else {
    app.locals.categories = categories;
}
});

Model:

var mongoose =require('mongoose');
var CategorySchema = mongoose.Schema({
title: {
    type:String,
    required:true
},
slug: {
    type:String
   }
});

module.exports = mongoose.model("Category", CategorySchema);
like image 272
mlhazan Avatar asked Sep 09 '19 05:09

mlhazan


2 Answers

1. How to connect from terminal and mongo:

When you install MongoDB the authorization is disabled. So keep it like that for now. Create a root user in admin database:

Type: mongod in a terminal to run db, and then in another terminal run command mongo to run access mongo terminal

use admin
db.createUser(
  {
    user: "root",
    pwd: "pass123",
    roles: [ { role: "userAdminAnyDatabase", db: "admin" }, "readWriteAnyDatabase" ]
  }
)
 

Now create a database:

Run the use statement. If the database doesn't already exist, it will be created

use writeapp

To confirm the database created, you must insert some data otherwise it will not be created. db.testcollection.insert({ artist: "Mike" })

After that you have created root user and a new db. Now change mongodb config

nano /etc/mongod.conf 

Change the line to:

security:
   authorization: "enabled"

Now restart the db service from a terminal.

sudo systemctl restart mongod

check the status:

sudo systemctl status mongod

From now you need password to login to mongo

mongo -u root -p pass123 --authenticationDatabase admin

Let now create a user in admin database but also give admin privilege to a specific database like writeapp

`use admin`

`db.createUser({user:"writetApp", pwd:"writeApp5299", roles:[{role:"dbOwner", db:"writeapp"}]});`

To check the user:

db.getUsers();
[
   {
    "_id" : "admin.root",
    "userId" : UUID("8f6c1295-a261-4057-9a29-8a9919437841"),
    "user" : "root",
    "db" : "admin",
    "roles" : [
        {
            "role" : "userAdminAnyDatabase",
            "db" : "admin"
        }
    ],
    "mechanisms" : [
        "SCRAM-SHA-1",
        "SCRAM-SHA-256"
    ]
},
{
    "_id" : "admin.writeApp",
    "userId" : UUID("ee148506-1860-4739-80db-17352e0e2ccb"),
    "user" : "writeApp",
    "db" : "admin",
    "roles" : [
        {
            "role" : "dbOwner",
            "db" : "writeapp"
        }
    ],
    "mechanisms" : [
        "SCRAM-SHA-1",
        "SCRAM-SHA-256"
    ]
 }

Exit from mongo and login

`mongo -u "writeApp" -p writeApp5299 --authenticationDatabase "admin"`

Now if you have created the user in other db rather than admin then --authenticationDatabase "yourdbname"

Now to execute command from mongo.

 `use writeapp`

 ` db.testcollection.find();`

2. How to connect from node.js:

Procedure1:

const mongoURI = 'mongodb://writeApp:[email protected]:27017/writeapp';

const db = mongoose.connect(mongoURI, { useNewUrlParser: true });

Procedure2:

mongoose.connect('mongodb://writeApp:[email protected]:27017/writeapp?auththSource=writeapp&w=1',{ useNewUrlParser: true });

Both works either you use authSource or not, not a problem at all:

The Problem: server.js or app.js runs first in any node.js app or the entry point which loads all modules/middleware/routes etc.
Now if any of the route has another mongodb connect which has issue, the application error simply shows the error that I showed:

command find/insert/update requires authentication

But the problem is it does not show which file has the issue. So it was time-consuming to look for the issue in each route. So the problem is solved

like image 161
mlhazan Avatar answered Sep 28 '22 11:09

mlhazan


Looking at the results from db.geUsers() in your post, the target database and authentication database are different. You can change the connection URL with a query parameter called authSource=admin where admin is your authentication credential source.

Connection URL:

const mongoURI =
  "mongodb://writeApp:[email protected]:27017/writeapp?authSource=admin";

OR

const mongoURI =
  "mongodb://writeApp:writeApp9779@localhost:27017/writeapp?authSource=admin";

Update: On User Roles

dbAdmin role that is assigned to writeApp user doesn't provide read/write on non-system collections. Try granting read or readWrite to the user.

db.grantRolesToUser( "writeApp", [ "read" ] ) //OR
db.grantRolesToUser( "writeApp", [ "readWrite" ] )

NOTE: authSource URI option docs

like image 23
ambianBeing Avatar answered Sep 28 '22 09:09

ambianBeing