MongoDB custom user roles - "user is not allowed(...)" - node.js

I created a free tier cluster on MongoDB Atlas (it has 3 shards) and I want my Node.js app to connect with a database I created there, using a specific user, that will be restricted from using any other database than the one inteded for this app.
So step by step.
I create a database called, let's say, test.
I create a role here - I go to Security -> MongoDB Roles -> Add New Custom Role and I give it all Collection actions and all Database actions and roles to test
Time for a user, so again Security -> MongoDB Users -> Add New User and I assign a previously created role to it so it has access only to test database. So now I have 2 users - atlasAdmin and my created user.
That's where the problem occurs, when I use admin user in my app to connect, .find() or .create() it works fine all the time. With a user with custom role, it works for like 10mins/1 connection (until I shut down the local server I have my node app on) and the next time I get an error that "user is not allowed to perform action (...)".
I tried everything, tinkering with a string I use to connect, updating mongoose (I use it in my app), creating user and custom role using mongodb shell but nothing seems to work.
HOWEVER:
if I have this custom user, my app connects with it to the database and it works, then on the next connection it stops working AND I go here and just click UPDATE USER without changing anything there (I just click edit next to the user and then update) then wait for the cluster to make changes, it will work again for like +/- one connection.
everything works just fine if my app uses admin account
Anyone had similar problem? Screenshot of the error I was also thinking that it might be because of how many times I try to connect with mongo from the app (I use nodemon so everytime I save a file with changes, server restarts, thus connecting to database again) but I think that's not the case - if it was, why would I be able to make it work with admin user?
The string I use to connect with mongo:
// DATABASE SETUP
var dbURL = 'mongodb://[cluster0:port],[cluster1:port],[cluster2:port]/test?ssl=true&replicaSet=Cluster0-shard-0&authSource=admin&retryWrites=true';
var options = {
useNewUrlParser: true,
dbName: "test"
user: [login],
pass: [pass]
};
mongoose.connect(dbURL, options);

I have also encountered this problem on Atlas Free tier, not just on NodeJS but Java as well
For now, you can try mitigating this problem by using a default role instead of having a custom one
On the MongoDB Users tab, click "Edit" on your user => Add Default Privileges
Picture 1
Then select "readWrite" and type your database name on the first field, then save the user
Picture 2
Or, if you want database administration, add another field with "dbAdmin" role
Picture 3
At least that's how I solved it. I hope this helps.
Side note: You can also use the shorter connection string (MongoDB+SRV) and it would still work.

Related

Getting 'Could not find stored procedure' error calling SQL Server stored procedure in Node JS from AWS RDS database

We always normally work in Azure where I write around 200 stored procedures a year in their SQL Server database.
We had to create a SQL Server database in AWS-RDS and still call it in our Node APIs like usual. I was able to quickly and easily set up the AWS DB in SQL Server Management Studio so I do know the credentials.
I created several tables and several stored procedures with no problems and tested to make sure they worked there. When I called them like I normally do in Node, I found I was getting an error
Could not find stored procedure
I went through forums all over but most of the data pertains to MySQL instead of SQL Server, and after trying everything I saw in the forums have not been able to complete what should be a very simple process. I would imagine there is some simple thing I missed, but after 2 days it is time for some fresh ideas.
I am setting up the credentials like this:
var awsConnection = {
host : process.env.RDS_HOSTNAME,
user : process.env.RDS_USERNAME,
password : process.env.RDS_PASSWORD,
port : process.env.RDS_PORT
};
I am using the endpoint provided by AWS for the host, the username and password I use to login to SQL Server Management Tool (which works). The port number is the one specified by AWS (1433 - the default for SQL Server).
I call it in my api like this:
await sql.connect(connectionAWS).then(pool => {
// Stored procedure
console.log("awsConnection INSIDE: " + JSON.stringify(awsConnection));
return pool.request()
.input('repId', sql.VARCHAR(40), repObj.RepID)
.execute('UserExistsBD');
}).then(async result => { ...
I added the console.log to see if we were getting past the login and it appears that we do. I also used Telnet to make sure the endpoint/port combo work and they do. I also checked AWS to make sure the Subnets, Route tables, and gateways were good and to make sure my IP Address was white listed. Any ideas would be very much appreciated!

Syncing Azure Easy Table with WHERE clause

I'm developing a Xamarin.Forms app which uses an Azure app service with SQL database linked through EasyTables. I've run the samples and successfully tested querying tables etc on the server and enabled offline sync so as a localdb is created.
I've created the store, defined the table & sync'd it, however I want to be able to query it somehow with a where clause - is that possible? Can I add a where clause to the client.GetSyncTable line?
var store = new MobileServiceSQLiteStore("localstore.db");
store.DefineTable<Journey_Stages>();
client.SyncContext.InitializeAsync(store);
tbl_Stages = client.GetSyncTable<Journey_Stages>();
Some of the tables I'm pulling down will grow over time & are linked to individual user profiles, so I only want data which belongs to that user and I don't want to be bringing down masses of data each time, preferably let the server handle that and only bring down what I need on a user by user basis.
Thanks,
Steve
You should add this filtering logic on the server side, so that each user's data isn't exposed to all your other users. See for example this sample if you are using the Node.js backend -- line 17 adds a WHERE clause for the table read query. If you have the .Net backend, similar logic would go in your table controller.
// Configure specific code when the client does a request
// READ - only return records belonging to the authenticated user
table.read(function (context) {
context.query.where({ userId: context.user.id });
return context.execute();
});

How to delete a database using node.js and MongoDB Atlas?

I'm new to MongoDB and node.js and I want to know how to delete a database.
I've searched for and I found that it is done with the dropDatabase() method. The problem is that it shows a MongoError: user is not allowed to do action [dropDatabase] on [test.]. I also searched for this error and the answer I found is that the user needs to be registered as Data Access Read Write. However, my user in mongo atlas is registred as Project Owner and as the answer says. I removed Project Owner and it still displays the error.
MongoClient.connect(uri, { useNewUrlParser: true }, (err, client)=>{
if(err) throw err;
console.log("Connected...");
const db = client.db("test");
db.dropDatabase();
console.log("asdfghj")
client.close();
});
In fact, whenever i searched to fix the problem typing Mongo atlas in the search bar, the results are like How to delete cluster in mongo atlas even though i'm typing delete database in mongo atlas. So i don't know if a database can be deleted in mongo atlas.
Thank you in advance.
Looks like you are confusing "Atlas Project" security with "Database Access".
If you are looking for removing a database from an Atlas Cluster, the "Database User" you are using to login in your Mongo Client needs to have "dbAdmin" role in the related database. You can then perform related operations using your database user via your Mongo client programmatically.
You can refer to https://docs.atlas.mongodb.com/security-add-mongodb-users/ for managing database users and security roles.
You can log into Atlas, click the cluster name, click the "collections" tab, then when you hover over the database name on the left, there will appear a garbage can icon, which will delete the DB (assuming your user has proper permissions)
If you want to delete the db in code, there's no way to do it directly from mongoose, but you can if you access the underlying mongodb driver:
mongoose.connection.db.dropDatabase(cb)

Authentication error when connecting to specific mongodb database

I am currently using nodejs with mongodb native driver. So my mongodb has been set with admin auth with root role, so I can log in using robomongo or command line just fine. So back to my project, I m able to connect to mongodb just fine if i set my connection string:
mongodb://admin:password#localhost:27017/
However, if I use this connection string:
mongodb://admin:password#localhost:27017/specificdb
It return as:
MongoError: Authentication failed
I am able to access the db using command and robomongo, is there anything I can do? I have added the admin user under the db, but still got the same problem.
The database you specify is the one you authenticate on. If the user is not known/has no roles for that database it cannot authenticate to it.
https://docs.mongodb.com/manual/reference/connection-string/
What you can do is either create the (or a new) user for that database or use an authentication database parameter.
this worked for me :
first solution on connection :
mongoose.connect('mongodb://....', {
// add this line
authSource:"admin",
....
})
or second solution add to the uri "?authSource=admin" :
mongodb://user:password#host/yourDB?authSource=admin
** to note that I am using mongoose and this is the documentation specefic statement and the url :
authSource - The database to use when authenticating with user and pass. In MongoDB, users are scoped to a database. If you are getting an unexpected login failure, you may need to set this option.
https://mongoosejs.com/docs/connections.html#options

Run mongodb script once to insert initial data

I have a chicken and egg problem with my node server in which you need to have a user with a certain role that has certain permissions to be able to log in and start creating more users, roles, etc.
I would like to initialize the database such that I create an initial ADMIN role and initial admin user that has that role.
I.E. started with a script and ran into problems:
use mydb
db.roles.insert({
name: "ADMIN_ROLE",
description: "Administrative role",
permissions: ['ALL']
});
db.users.insert({
username: "admin",
password: "password",
role: ??? (get ADMIN_ROLE _id from above)
});
Basically I ran into a couple of problems:
1. not really sure if I can script like this.
2. How to get ADMIN_ROLE id to store in new admin user
Another idea:
Write a quick node app that connects to mongodb and inserts the proper stuff. Anyone done this before.
And yet another:
Does anything like ruby rake exist for node/mongo. I.E. the initial seed may not be the only data I need to 'manually' mess with. I.E. I might need to patch the database at some point in time. Would be nice to create patch #1 as the initial seed, and then be able to write future patches if necessary and be able to. I.E. anything like rake migrate?
Any other ideas on how to seed a mongo database?
Shoot just found this:
https://github.com/visionmedia/node-migrate
and
https://npmjs.org/package/mongo-migrate
Exactly what I was looking for.

Resources