belst / rusty-diesel-rocket

Batteries Included (not yet)
8 stars 1 forks source link

Access Control System #5

Open belst opened 6 years ago

belst commented 6 years ago

Ideas for an access control system based on RBAC:

Relationships:

User n<--->m Role n<--->m Permission

Maybe User n<--->m Permission aswell?

Role:
Name
Description
Level

Permission:
Name
Description

If they are not database based, every Role or Permission should be its own type, so they can be used as Request Guards. (They should probably be anyway, even if they are database based.)

Database has the advantage that it is possible to create a very dynamic and customizable system where u can add and remove permissions/roles any time. But you lose the nice static typing and Guard system from Rocket.

Unfortunately we cannot use Enums here, because Enum variants cannot be used as a Guard.

For level checks, something like typelevel integers would be nice. eg (or until they are available: https://github.com/paholg/typenum):

#[get("/private")]
fn get_private(_level: Level<GE<7>>) // level must be Greater or Equal to 7
{
  // return private data
}
alko89 commented 6 years ago

I had to read about this Guard system and rankings in Rocket. I didn't know much about it. I just started coding withouth the actuall knowledge of the framework.

Do you have any more resources to read? The Rocket guide is kind of vague. Anyway. I personally would like to have permisions in the database.

When I started my project I thought I could make it work like Pyramid. But it seems that would not be the best option due to the way Rocket works.

Pyramids only has Users and Roles with different permissions. Its not level based (something that a manager can access, can be unaccessable for admin), you just check if the user is in role. The level based system seems more Unix-like.

belst commented 6 years ago

with RBAC you can have both. You can either ask if a user is in a group, if a user has a specific permission or if a user has a certain level.

So if you ask if the User is a Moderator, and Administrator might not be able to access it. but if you for example say, Moderator is level 7 and Administrator is level 10 and you ask for level >= 7 both Administrator and Moderator can access it.

This is just one possible implementation and does not allow for sibling Groups/forks in the group hierarchy.

For a full RBAC implementation a tree of groups would be needed i think. So you can do stuff like this:

           +-->Administrator<--+
           +                   +
Frontend Moderator           Editor
           ^                   ^
           +                   +
Community Moderator          Author

where you can have separate subtrees of groups .

This is not specific to Rocket.

Rocket would just allow to specify the required permissions/roles/levels as route parameters via Guards.

alko89 commented 6 years ago

But if I understand, these permissions won't work using a database. Is there a way around this?

Worst case, can these permissions be loaded from the database at compile time, to be able to work with Guards?

belst commented 6 years ago

You need some way to specify if a user has a specific permission. So something needs to be in the database. For example List of groups the user is a member of.

But the groups and Permissions itself would not need to be in the database. It wouldnt even make sense to have them in the database because you can only change them at compile time.

edit: if I find some time I'll implement a prototype today.

edit: small permission/group models (no integration into Rocket whatsoever atm, no level stuff either):

https://play.rust-lang.org/?gist=e25a6d594812bc95c41bffd93622041b

alko89 commented 6 years ago

So we have to add a column to the user to store user groups and a static object in the code itself with defined groups.

You would use typelevel integers for that? I'll have to serch the web for what that is 😄

veotax commented 4 years ago

You can use: https://github.com/casbin/casbin-rs