onury / accesscontrol

Role and Attribute based Access Control for Node.js
https://onury.io/accesscontrol
MIT License
2.21k stars 178 forks source link

Add action, possession info to Permission instance #36

Open ismail-ab opened 6 years ago

ismail-ab commented 6 years ago

Hi,

In the IAccessInfo I can only see denied. Is "granted" missing ?

Thank you Ismail

onury commented 6 years ago

Hi. IAccessInfo only has a denied flag. See constructor of Access class for details.

Closing this. Pls continue thread if you need to.

ismail-ab commented 6 years ago

Hi,

Sorry, my question was more about naming variables and functions which deal with the function granted. I mean, in my application, I only check if my permissions are granted, for this I declare my permissions like this:

const queryInfo: IQueryInfo =  {
    resource: 'user',
    action: 'create',
    possession: 'any'
  }

Then I get the "granted" value with accessControl.permission(...).granted, and I want my accessInfo to be like:

const accessInfo: IAccessInfo = {
    resource: 'user',
    action: 'create',
    possession: 'any',
    granted: true // result of accessControl.permission(...).granted
  };

As I check if my permission is granted, I want to deal with a value called "granted" which is not present in the interface IAccessInfo. There is only denied. Of course "denied" means "not granted", but I want my roles system to drive in one way: granted = isGranted, and not denied = !isGranted

Thanks, Ismail

onury commented 6 years ago

First of all, both your IQueryInfo and IAccessInfo objects should have a role property.

Second, as mentioned before, IAccessInfo does not have it. granted is a property of AccessControl~Permission instance.

An access is not granted simply by setting some value to true. Internally, it's granted or denied by resource attributes. So if a role is allowed even only a single attribute of a resource, the permission query will return granted as true. If no attributes are allowed, it will return granted as false. But you should take attributes into account to see what (or how much of it) is actually granted.

That denied property of Access inner class only indicates the initial state. It's actually an internal flag, you shouldn't really depend on.

An Access instance or IAccessInfo interface defines a privilege. For checking whether that privilege is granted or denied, you should make use of the Permission inner class (and IQueryInfo interface).

Granting Access

// granting "video" resource for the "user" role, with all attributes:
ac.grant('user').create('video');
// is equivalent to
ac.grant('user').create('video', ['*']);
// is equivalent to
const access: IAccessInfo = {
    role: 'user',
    resource: 'video',
    action: 'create',
    possession: 'any',   // defaults to "any" if omitted
    attributes: ['*']  
};
ac.grant(access);

Denying Access

ac.deny('user').create('video');
// is equivalent to
ac.grant('user').create('video', []); // grant no attributes
// is equivalent to
const access: IAccessInfo = {
    role: 'user',
    resource: 'video',
    action: 'create:any',
    attributes: []   // <—— no attributes
};
ac.grant(access);

Querying for Permission

const permission: Permission = ac.can('user').create('video');
console.log(permission.granted);

or you can:

const query: IQueryInfo = {
     role: 'user',
     resource: 'video',
     action: 'create',
     possession: 'any'
 };
const permission: Permission = ac.permission(query);
console.log(permission.granted); 
ismail-ab commented 6 years ago

Hello,

Yeah of course the role was missing in my code above but I add it in another step in my code, that's why it was not present in this issue.

To check if I have the permission I do the last example you said:

const query: IQueryInfo = {
     role: 'user',
     resource: 'video',
     action: 'create',
     possession: 'any'
 };

const permission = ac.permission(query);

Then I do this:

const response: _TYPE_ = {
     role: 'user',
     resource: 'video',
     action: 'create',
     possession: 'any',
     granted: permission.granted
 };

I use the Permission inner class. The query has type IQueryInfo, but what is the type of this object 'response' above ? I return this to the front, then in front I authorize access to my components depending on the value granted in the object response (of course which depends on attributes)

Currently I created an interface IAccessInfo which extends IQueryInfo and I assign this type to my object response :

interface IAccessInfo extends IQueryInfo {
  granted: boolean;
}

I named it IAccessInfo because it is looking to be the closest name type for my case. But I hope there is a better solution

Thank you for the answer ! Ismail

onury commented 6 years ago

Don't do that. IAccessInfo is a core interface already.

You have the Permission class.

const permission: Permission = ac.permission(query);

This has granted: Boolean, roles: string[], resource: String, attributes: string[] properties you need (and more)...

I see you also need action and possession in the Permission instance. I can consider this as a feature request. Until implemented, you can do this:

interface IResponse extends IQueryInfo {
  granted: boolean;
  attributes: string[];
}

const query: IQueryInfo = {
     role: 'user',
     resource: 'video',
     action: 'create',
     possession: 'any'
 };
const response: IResponse = Object.assign({ 
    granted:  permission.granted,
    attributes: permission.attributes
}, query);
ismail-ab commented 6 years ago

Oki, this is exactly what I need, I hope we'll have this feature very soon !

Thank you very much ! See you !

ismail-ab commented 6 years ago

By the way, this issue is labelled "invalid", should it be changed to "feature request" or else ?

onury commented 6 years ago

Yes. Now that we have an understanding, I'm re-opening this issue as a feature-request.

ismail-ab commented 6 years ago

Oki thank you ! Actually it is my first issue on Github, I'm very happy we have an understanding, I'll try to be more explicit for my future issues on Github :)

onury commented 6 years ago

You're very welcome. No worries at all.

HimanshuZade10 commented 6 years ago

@onury is there any other medium to get in touch with you.

himanshugogroup commented 2 months ago

Is there any way we can check do something like as updateOwn based on user belong to team A or team B

ac.grant('member')
  .createOwn('post', ['*'])
  .readOwn('post', ['*'])
  .updateOwn('post', ['*'], {
    // Condition: Only allow update if the user has the 'canUpdatePosts' property
    condition: (user, resource) => user.team == 'A',
  })
  .deleteOwn('post', ['*'], {
    // Condition: Only allow delete if the user has the 'canDeletePosts' property
    condition: (user, resource) => user.team == 'A',
  });

Also can package itself provide enums for actions like createOwn for dynamic value