tensult / role-acl Goto Github PK
View Code? Open in Web Editor NEWRole based access control using actions, attributes and sync and async conditions
Home Page: https://www.tensult.com
License: Other
Role based access control using actions, attributes and sync and async conditions
Home Page: https://www.tensult.com
License: Other
Hi, I try to use this library on react-native. And I got warning
Require cycles are allowed, but can result in uninitialized values. Consider refactoring to remove the need for a cycle.
[Wed Jul 01 2020 06:55:03.110] WARN Require cycle: node_modules/role-acl/lib/src/conditions/util.js -> node_modules/role-acl/lib/src/conditions/StartsWithCondition.js -> node_modules/role-acl/lib/src/conditions/util.js
How to solve this problem ?
Hey, your lib looks not bad but we need own condition functions
function checkOwner(context) {
// ... own specifc logic
return allowed;
}
ac.grant('user')
.condition(checkOwner)
.execute('update')
.on('posts');
ac.can(user.roles)
.context({user, post, org})
.execute('update')
.on('posts');
In a prefect world, the checkOwner function can be async to allow additional database lookups without the need to bind this logic on the context creation.
I'm writing type definitions for another developer's library and they're using role-acl. One of the arguments they're using is of the AccessControl class. If I write import { AccessControl } from 'role-acl'
, role-acl is not recognised as a module (see error message in title). How do I access the AccessControl class in order to use it as a type? Thank you.
Hi, so I've dug thru the source code and found that the only "attributes" of a grant allowed are the role, resource, action, attributes, and condition.
However, I'd like to specify the error message when defining the ACL. I know this isn't possible now, but could you please add this feature? Thank you!
Hey,
I have the following error when i try to use the lib (v3.3.3 - installed via npm):
Cannot find module './lib' from 'index.js'
To fix it I change the file /index.js
with:
var AC = require("./lib").AccessControl;
=>
var AC = require("./lib/src").AccessControl;
:)
Hello,
When I reproduce the example, the condition does not pass. I use the latest version (3.3.0) installed via yarn add role-acl
.
Furthermore, is it possible to pass a path to access nested objects?
For example: $.owner.tenant._id
const AccessControl = require('role-acl')
test('Condition', async () => {
const ac = new AccessControl()
ac.grant('user').condition({
Fn: 'EQUALS',
args: {
'requester': '$.owner'
}
}).execute('edit').on('article')
const permission = ac.can('user').context({ requester: 'dilip', owner: 'dilip'}).execute('edit').on('article')
expect(permission.granted).toBeTruthy()
})
Thx for your great job!
Hi, I maintain a library that depends on role-acl
and accesscontrol
, and while I've tried to work around the now asynchronous methods, it's ridiculously hard, especially when extendRole
is async.
Can you add an option to make the methods synchronous? 99% of us don't need the methods to be async... please and thank you.
Hi,
Thanks for the great tool. I am evaluating the 4.1.0 version of it. I run into an issue.
My grant list looks like this:
{ role: "terminalDispatcher", resource: "user", action: "read", attributes: ["*"] }, { role: "terminalDispatcher", resource: "user", action: "edit", attributes: ["*"], condition: { Fn: "EQUALS", args: { requester: "$.owner" } } }, { role: "terminalAdmin", resource: "user", action: "read", attributes: ["*"] }, { role: "terminalAdmin", resource: "user", action: "edit", attributes: ["*"], condition: { Fn: "EQUALS", args: { requester: "$.owner" } } }, { role: "terminalAdmin", resource: "user", action: ["edit", "delete"], attributes: ["*"], condition: { Fn: "EQUALS", args: { allowedRole: "terminalDispatcher" } } }
My intentions are:
Using the above grants I have initialized AccessControl, here is the code snippet:
let targetEditTerminalDispatcher = { allowedRole: 'terminalDispatcher' }; let targetEditTerminalAdmin = { allowedRole: 'terminalAdmin' }; let grantList = getUserRoleACL(); const ac = new AccessControl(grantList); const readPermission = await ac.can('terminalAdmin').execute('read').on('user'); const editSelfPermission = await ac.can('terminalAdmin').context({requester: 5, owner: 5}).execute('edit').on('user'); const editNotSelfPermission = await ac.can('terminalAdmin').context({requester: 5, owner: 6}).execute('edit').on('user'); const editTerminalDispatcher = await ac.can('terminalAdmin').execute('edit').with(targetEditTerminalDispatcher).on('user'); const editTerminalAdmin = await ac.can('terminalDispatcher').execute('edit').with(targetEditTerminalAdmin).on('user'); const editTerminalAdminRANDOM = await ac.can('terminalDispatcher').execute('edit').with('ABC').on('user');
All grant results good except for editTerminalAdmin
and editTerminalAdminRANDOM
.
I was not expecting them to be granted = true, but they are.
Am I missing something or do I need specifically deny permission?
Hello,
First of all, I want to give you a big thanks for this great library.
In some case, I have to use the condition feature which requires some check in the database for certain role. Admin users can do anything on the resource, but basic users can only maintain the resources in the room they belong to.
For example, basic user 1 can edit the resources A, B and C, and basic user 2 can edit resources C and D.
In order to minimize performance impact, I would like to retrieve the grant associated to the resource / action and then provide the context (LIST_CONTAINS retrieved from database) only if required.
One option is to first check on my side if the role requires to pass the context, but this means that I must have the permission knowledge in my business module. Additionally, it increases the maintenance of my application in case of any change in the authorization.
Another option is to use the custom condition, but it's not compatible with the grant object definition. I found that custom condition are removed when the json object is cloned in the normalizeGrantsObject method.
Does it makes sense for you ?
Thanks
Hey,
I really love the api of this library but It's a shame it's only saved in memory.
it this possible to think about extending with db, redis... ?
I'm testing whether an argument equals null
in a condition with the expectation that it should return true
.
Instead, it returns false
Permission {
_: {
role: 'user',
resource: 'abc',
context: {
AssignedId: 'f1346471-6adf-431e-9602-656fa46c78b1',
CompletedAt: null,
userId: 'f1346471-6adf-431e-9602-656fa46c78b1',
},
attributes: []
}
}
{
resource: 'abc',
action: ['update'],
attributes: ["CompletedAt"],
condition: {
Fn: 'AND',
args: [
{ 'Fn': 'EQUALS', 'args': { 'userId': '$.AssignedId' } },
{ 'Fn': 'EQUALS', 'args': { 'CompletedAt': null } }
]
}
}
I've also tried without the Fn: 'AND' condition and see the same.
This is a great library that I was using in my project, thanks! I especially love how I can express my permissions business logic using
ac.grant('user').execute('action').where(context => SOME LOGIC).on('resource')
However I came upon a wall. I would like to use an asynchronous function in the where
clause. But the library does not support that. Any idea how I can go about this?
E.g. I would like to pass a resource_id
as the context, and the function would perform an asynchronous database call to ensure that the user has been associated with that resource.
Honestly 90% of the examples in the README are synchronous and I literally can't tell whether a method is async or not (e.g. I was surprised when extendRole
was failing, and turns out it was async for some reason) because of it.
It would be nice to just say "hey all these functions are synchronous on <4.0" at the top of the documentation and update the examples of async methods to reflect that. It's just confusing because some are async, some are not, and I can't tell by reading the README!
P.S. to make it easier for people to migrate between versions, please maintain a changelog by using something like https://github.com/sindresorhus/np for every version you release.
Hi,
First I'd like to mention that I like using this module, the conditionals make it very powerful to deal with fine grained access control.
After updating to v3.0.7 I get the following error
{"column":32,"file":"module.js","function":"Module.load","line":573,"method":"load","native":false}],"stack":["Error: Cannot find module './lib'"," at Function.Module._resolveFilename (module.js:555:15)"," at Function.Module._load (module.js:482:25)"," at Module.require (module.js:604:17)"," at require (internal/module.js:11:18)"," at Object.<anonymous> (/api/node_modules/role-acl/index.js:1:10)"," at Module._compile (module.js:660:30)"," at Object.Module._extensions..js (module.js:671:10)"," at Module.load (module.js:573:32)"," at tryModuleLoad (module.js:513:12)"," at Function.Module._load (module.js:505:3)"," at Module.require (module.js:604:17)"," at require (internal/module.js:11:18)"," at Object.<anonymous> (/api/something.js:6:23)"," at Module._compile (module.js:660:30)"," at Object.Module._extensions..js (module.js:671:10)"," at Module.load (module.js:573:32)"],"level":"error","message":"uncaughtException: Cannot find module './lib'"}
When looking at the node_modules/role_acl directory the 'lib' directory is missing. It seems that the package is incomplete. Going back to v3.0.6 resolves the error.
For example: if the value of expression contain "fun:getUserDepartment", it should call "getUserDepartment" function to return the current user's department info.
Maybe need register this custom function to ac with its context.
ac.registerConditionFunc('getUserDepartment', getUserDepartment, userContext)
I've been trying to use grant conditions on a context which has a nested Object similar to below.
Context object:
{
"val": "abc",
"item": {
"itemValue": "abc"
}
}
condition:
condition: {
Fn: 'EQUALS',
args: {
'val': $item.itemValue
}
}
The docs suggest that an JSON path similar to $item.itemValue would work but the context test never works.
Are nested objects in the context supported? Could you provide examples in the tests if they are?
Two grants are loaded from database.
const role1 = {
role: 'role1',
resource: 'person',
action: ['create', 'view', 'treat'],
attributes: ['*']
}
and
const role2 = {
role: 'role2',
resource: 'person',
action: ['update', 'greet', '!create'],
attributes: ['*'],
}
With following test code.
const grantsToLoad = [role1, role2]
ac.setGrants(grantsToLoad)
const roles = ac.getRoles()
const permission = await ac.can(roles).execute('create').on('person')
expect(permission.granted).toEqual(false)
I expect create
to be denied as it being explicitly mentioned in action of role2
. But the desired result is the permission to create
is granted. Thus explicit denial is not taken into consideration.
The code behind this behavior is in filter
of getUnionAttrsOfRolesSync
where role2 is being filtered out in favor of positive action.
Lines 366 to 377 in 321d013
I feel it would be very useful to write conditions that can compare values passed into the context against each other, instead of just being able to compare against static values. This would be particularly helpful for checking to see if a user is the owner of a resource.
Something like this could be done outside the RBAC check, but this would help encapsulate all RBAC logic.
For example,
AccessControl.can(roles)
.with({ requester, target })
.execute("update")
.on("user");
...
condition: {
Fn: 'EQUALS',
args: {
requester: '$target'
}
}
there is this note in the readme:
NOTE: getValueByPath is available in versions >= 4.5.5
but on NPM you only have version 4.5.4 published. Is there a reason why this isn't published yet?
I'm trying to use the getValueByPath
method.
This is a fork of AccessControl with MIT license.
You cannot remove the copyright notice.
Please include it in both the README and license.
Also remove this and any other false notice in the code please. You can only mark the portions of the code that you actually develop.
You should respect OSS developers. Open-Source is not "free" code for you to label.
Hi- your library is really enjoyable and intuitive to use! I ran into an issue with the AND condition; if you pass it any async custom conditions as args, it does not await those conditions.
Example- given the following grant definition:
{
role: 'manager',
resource: 'customers',
action: 'PUT',
attributes: ['*'],
condition: {
Fn: 'AND',
args: [
{ Fn: 'custom:sameCustomer }, //sync
{ Fn: 'custom:userCanAccessResource' }, // async
],
},
},
custom:userCanAccessResource
is not awaited before permission is evaluated- permission.granted
evaluates to "true" as long as all other conditions are met.
Even if you remove custom:sameOwner
, you get the same result, so it doesn't seem to be an issue with combining sync with async conditions.
Looks like && Promise.resolve(elm) == elm
in the containsPromises
method is the culprit; if you comment out that condition, async custom functions passed to AND get awaited properly.
It would seem that removing this logic is the fix, but is there a reason that it's there & should not be removed?
Is it possible to extend a role via the Array Syntax
when loading from a DB? I am not able to find anything in the docs if this is possible and seems quite useful.
For example ('admin' extends 'user'):
let grantList = [
{ role: 'user', resource: 'video', action: 'create', attributes: ['*'] },
{ role: 'user', resource: 'video', action: 'read', attributes: ['*'] },
{ role: 'user', resource: 'video', action: 'update', attributes: ['*'] },
{ role: 'admin', extend: 'user' },
{ role: 'admin', resource: 'video', action: 'delete', attributes: ['*'] },
];
Can only replicate in 4.5.3 (4.5.2 seems to be fine). Using a standard import { AccessControl } from 'role-acl';
results in the following errors at build time.
node_modules/role-acl/lib/src/AccessControl.d.ts:320:16 - error TS1086: An accessor cannot be declared in an ambient context.
320 static get Error(): any;
~~~~~
node_modules/role-acl/lib/src/core/Permission.d.ts:62:9 - error TS1086: An accessor cannot be declared in an ambient context.
62 get roles(): string[];
~~~~~
node_modules/role-acl/lib/src/core/Permission.d.ts:70:9 - error TS1086: An accessor cannot be declared in an ambient context.
70 get resource(): string;
~~~~~~~~
node_modules/role-acl/lib/src/core/Permission.d.ts:83:9 - error TS1086: An accessor cannot be declared in an ambient context.
83 get attributes(): string[];
~~~~~~~~~~
node_modules/role-acl/lib/src/core/Permission.d.ts:92:9 - error TS1086: An accessor cannot be declared in an ambient context.
92 get granted(): boolean;
Hi there,
The library looks very promising and I really like the ability to define conditions for the permissions ๐
Wanna give it a try in my current project.
The only concern I have at the moment is the lack of a changelog and tagged versions so that I can easily switch between different versions.
Could you please tag versions and document changes between versions
Hi,
I wrote my grantobject and took it to acl like this, but i had error
const ac = new AccessControl();
ac.setGrants(grantsObject);
Class constructor CoreMongooseArray cannot be invoked without 'new'
(node:11861) UnhandledPromiseRejectionWarning: TypeError: Class constructor CoreMongooseArray cannot be invoked without 'new'
at initCloneArray.........
Extending roles does not work as expected.
Code sample is taken from documentation.
script.js
:
const roleAcl = require("role-acl");
const ac = new roleAcl();
ac.grant('user')
.execute('read').on('video')
.grant('admin')
.extend('user')
.execute('create').on('video')
.execute('update').on('video')
.execute('delete').on('video');
/path/to/script.js:8
.execute('create')
^
TypeError: ac.grant(...).execute(...).on(...).grant(...).extend(...).execute is not a function
at Object.<anonymous> (/path/to/script.js:8:6)
I'm exploring the possibility to implement the role-acl
lib in a project. I'm injecting it in my own ACL abstraction and everything looks good so far.
However, what I'm missing is an option to declare and register a custom condition Fn as a string and map it to a function. This way I'd be able to wrap more complex business logic and still to serialize and store the grant object.
I see there is custom functions support, which is an option to pre-process the definition and replace a custom condition string with JS function so that library process it, but a native library support would be much better. Not to mention it would open contribution possibilities (I can imagine a MONGODB_QUERY
condition...)
Here is sample API of what I have on my mind:
Signature
interface CustomConditionFns {
[name: string]: (ctx?: Record<string, unknown>, args?: unknown) => boolean;
}
condition.gte.ts
import { get } from 'lodash';
export type ARGS = { field: string; value: number };
export const conditionGte = (ctx: Record<string, any>, args: ARGS) => {
return +get(ctx, args.field) > args.value;
};
acl.ts
import { AccessControl } from 'role-acl';
import { conditionLte } from 'condition.lte'
const grantObj = fetchOrImportGrant();
const customFns = { 'GTE': conditionGte };
// We'd need to register custom conditions together with grant
// or before the grant to allow a type checking (unknown condition Fn)
// Register them together with the grant
const acl = new AccessControl(grantObj, customFns);
// OR first conditions, then the grant
const acl = new AccessControl();
acl.useConditions(customFns);
acl.setGrants(grantObj);
Usage (grant definition)
import { ARGS } from 'condition.lte'
const condition: { Fn: 'GTE'; args: ARGS } = {
Fn: 'GTE',
args: {
field: 'user.visits',
value: 1,
},
};
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.