Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MongoDB + Node JS + Role Based Access Control (RBAC)

Am currently learning MEAN stack, developing a simple TODO's app and want to implement Role Based Access Control (RBAC) for that. How do i set up roles & permission on MongoDB.

I want 3 roles (roles may look funny but this is purely to learn) :

  • GOD
  • SUPER HERO
  • MAN

GOD - similar to super admin, can do anything in the application. C,R,U,D permissions for TODO's and for other users too. Can Create a TODO & assign it to any SUPER HERO or MAN directly. Update or Delete either a TODO or a User at any point in time.

SUPER HERO - similar to admin, has super power to do anything on his personal Data - C,R,U,D for TODO's. Can't create any users. Can only Read & add comments for TODO's created by GOD & assigned to him/her.

MAN - Can only Read and add comments to TODO's assigned to him/her.

To sum it up :

GOD - C,R,U,D [Global Level] SUPER HERO - C,R,U,D [Private] + R,U [Assigned to him] MAN - R,U [Assigned to him]

I understand that i need to have USERS & ROLES collections. Where ROLES inturn should have PERMISSIONS etc. How do i wire them all ?

like image 313
BeingSuman Avatar asked Sep 28 '16 11:09

BeingSuman


People also ask

Should I use RBAC or ABAC?

The main difference between RBAC vs. ABAC is the way each method grants access. RBAC techniques allow you to grant access by roles. ABAC techniques let you determine access by user characteristics, object characteristics, action types, and more.

How can you implement role based access control RBAC )?

5 Steps to Implement Role-Based Access ControlCreate a mapping of roles to resources from step 1 such that each function can access resources needed to complete their job. Create security groups that represent each role. Assign users to defined roles by adding them to the relevant role-based groups.


2 Answers

I like names given to roles - GOD, SUPER HERO & MAN, easy to understand.

As you are using MEAN stack and much of routes validation happens on node, i would prefer keeping roles table simple.

Roles :

{
_id : 1,
name : GOD,
golbalPerms : true
},
{
_id : 2,
name : SUPER HERO,
privatePerms : true
},
{
_id : 3,
name : MAN
}

Users :

{
_id : 111,
name : Jesus,
roleId : 1
},
{
_id : 222,
name : BatMan,
roleId : 2
},
{
_id : 333,
name : Jack,
roleId : 3
}

When user logs in and sending user object back to client, make sure to replace roleId with corresponding role object from DB.

Coming to code on Node JS :

By completely understanding your usecase we can divide them into following methods -

  • CreateUser

  • CreateTodo

  • DeleteTodo

  • ReadTodo

  • UpdateTodo
  • CommentTodo

  • AssignTodo

Lets go step by step, CreateUser.

Routes code snippet :

app.all('/users', users.requiresLogin);

// Users Routes
app.route('/users')
    .post(users.hasPerms('globalPerms'), users.create);

In your Controller you can validate based on the input globalPerms, if validated allow to create user by calling next() else return with corresponding error message.

Now CreateTodo && DeleteTodo :

Both of them pretty much work on same logic with a small trick.

Routes code snippet :

app.all('/todos', users.requiresLogin);

// Users Routes
app.route('/todos')
    .post(users.hasPerms('globalPerms','privatePerms'), todos.create);
    .delete(users.hasPerms('globalPerms','privatePerms'), todos.delete);

For creating a Todo, globalPerms are with GOD & privatePerms are with SUPER HERO, both of them can be allowed.

Trick here will be in todos.delete method, just ensure user.id === todos.createById else SUPER HERO may go on to delete Todos created by GOD.

ReadTodo :

When a TODO is created it should have a createById stored likewise when a TODO is assigned to someone then assignedTo and assignedBy should be recorded too.

This makes lot of other operations easy to handle.

user.role.globalPerms - give GOD all TODO's data.

user.role.privatePerms - give TODO's either createdBy him/her or assigned to him/her.

user.role.globalPerms === undefined && user.role.privatePerms === undefined - its MAN and give TODO's which are only assignedTo him.

UpdateTodo & CommentTodo :

This is exact replica of what ReadTODO does so DIY

Last one, AssignTodo :

Simple one, loggedInUser.id === todos.createdById then he can assign it to anyone.

Two things to keep in mind here :

  1. As assigning part mostly happens on your UI (Angular) front, i have given that approach of checking loggedInUser.id === todos.createdById. Logged in user any ways will see all TODO's by read operation and can assign it to anyone he/she likes.

  2. Make sure a SUPER HERO can only assign a TODO to himself or other SUPER HERO or to a MAN but not to GOD. How you show Assign to options on UI front is out of scope of this question. This is just a heads up.

Hope this was clear.

NOTE : There was no necessity to give permissions to MAN in Roles collection & we managed all possible operations with out that.

like image 70
swetha akula Avatar answered Sep 20 '22 15:09

swetha akula


This is a very broad question which can be solved in many ways.

You have added that you are using MEAN stack therefore I'll restrict my question to that.

One thing that you haven't included in the whole question is what kind of authentication architecture are you using. Let's say you are using token based authentication, generally people these days use it.

We have 3 types of users. You have different options available to differentiate between type of tokens as well.

  1. Different Collection (mongoDB) or Redis sets where they will be stored
  2. The encrypted token will have type of the user as well etc.. (This will come in handy if you don't need to store tokens on the backend, you can just decrypt and check)

    • It will completely depend on use case.

Now, before allowing any user's entry to user specific route make sure that you are checking the token first.

Example

app.post('/godlevelroute', godtokencheck, callrouteandfunction);
app.post('/superherolevelroute', superheroroute, callrouteandfunction);

You must send token in header from angular and then you can take the data out from the header and then you can check if that specific user has permission to go through that route or not.

Let's say a god level user is logged in then he'll have the godleveltoken with him and we'll check that first before allowing him to access that route or else you can just show error message.

This can be your sample token checking function on server end

function checkToken(req, res, next) {
var token = req.headers['accesstoken']; //access token from header
//now depending upon which system you are following you can run a check
};

Node Module Suggestion : https://www.npmjs.com/package/jsonwebtoken

Now coming to frontend part. You are using angular based on what you have written, you can intercept the token before showing any page.

You can go through this blog to get a pictorial representation of what I have tried to explain. Click Here

like image 32
Gandalf the White Avatar answered Sep 18 '22 15:09

Gandalf the White