DDtKey / protect-endpoints

Authorization extension for popular web-frameworks to protect your endpoints
Apache License 2.0
211 stars 16 forks source link

Support for allowing 1 permission or the other #67

Closed flaxeneel2 closed 10 months ago

flaxeneel2 commented 10 months ago

Hi there! I wanted to make it so the user either has ROLE_ADMIN OR has a specific permission, instead of the user having both. Is this supported?

// User should be ADMIN with OP_GET_SECRET permission
#[actix_web_grants::protect("ROLE_ADMIN", "OP_GET_SECRET")]
async fn macro_secured() -> &'static str {
    "some secured info"
}

(taken from docs) From what i understand here, the user woiuld have to have both ROLE_ADMIN and OP_GET_SECRET. I wanted it so a certain permission can inherit other permissions. I am writing a custom extractor so i could theoretically add all the inherited permissions when i see a certain permission, but I was wondering if there was a built-in way to do so.

Thanks!

DDtKey commented 10 months ago

Hi, sure, it's possible You can use any combinations (and nests them) by all and any attributes

For the example above:

// User should be ADMIN OR OP_GET_SECRET permission
#[actix_web_grants::protect(any("ROLE_ADMIN", "OP_GET_SECRET"))]
async fn macro_secured() -> &'static str {
    "some secured info"
}

There are some examples in readme and examples folder.

Hope it will help, any questions are welcome.

DDtKey commented 10 months ago

But there is no built-in mechanism to build a hierarchy of roles/permissions.

I have had an idea to support inheritance of authorities, but it should be designed good enough to be clear.

It would require providing some predefined tree of authorities to the middleware. Like:

guest
-> user
   -> moderator
      -> admin
         -> superuser

Just to be able to check the hierarchy. And I think we should explicitly indicate that we want to take into account inheritance in the macro

flaxeneel2 commented 10 months ago

Hi there Thank you for your response! Yeah looking at the example, any seems to be exactly the thing I am looking for. I will give it a shot

As for the design of the inheritence, I can't say with certainty what would be a good method, but maybe an array in the macro, where it goes from the widest scope, to more and more minute scopes? for ex

// User should be ADMIN or have OP_GET_SECRET permission
#[actix_web_grants::protect_scoped(["ROLE_ADMIN", "OP_GET_SECRET"])]
async fn macro_secured() -> &'static str {
    "some secured info"
}

where if the user has the first in the list, it will skip checks for all, and so on

though then it might get tedious if you have a lot of possible permissions, plus this is basically working in a very similar way to any.

Maybe another thing that could be done is a marker for a struct, for ex

enum UserPermissions {
    CreatePost
    #[do_not_inherit]
    ViewPrivateMessages
}

#[inherit_from(UserPermissions)]
enum AdminPermissions {
    DeletePost
}

so the admin would always inherit all the permissions from UserPermissions but will still have to have relevant permissions in itself, with an option to mark any permission as do not inherit so those permissions are skipped during the inheritence (such as ViewPrivateMessages in this case, if you dont want ur admins snooping around user's private messages, this is just an example), though idk how that would work internally.

Regardless, I wish you the best of luck implementing authorities inheritence, and thank you once again for your help!