It would be good to require, for example, an ACL that requires both a static and a dynamic role in order to pass.
In my project there is a static role called 'admin'. I want some actions to be available only to users who have both 'admin' and '$owner' roles. At the moment my only workaround is to write a separate resolver to check these two roles, which isn't scaleable.
I believe you can define a combined role (say super) and add admin and $owner as principals to super using role mapping model.
That is useful to know and I will migrate my code to that for the meantime
but I think it would be better to commit this to code, rather than a Role
and RoleMapping that exist in the database, and are hard to see from the
ACL definition in the model JSON.
On 11 Sep 2015 4:51 pm, "Raymond Feng" [email protected] wrote:
I believe you can define a combined role (say super) and add admin and
$owner as principals to super using role mapping model.—
Reply to this email directly or view it on GitHub
https://github.com/strongloop/loopback/issues/1666#issuecomment-139582301
.
We're heading to that direction. See an example at https://github.com/strongloop/loopback-acl-route/blob/master/test/route-acl.test.js. Please note that's for the route-based ACLs but we intend to improve the model-based ACLs with similar capabilities.
Here's what I'd like to see:
// before
{
principalType: 'role',
principalId: 'admin',
permission: 'ALLOW',
accessType: 'READ'
}
// proposal
{
roles: ['admin', '$owner'],
accessType: 'READ',
permission: 'ALLOW',
priority: '100' // explicit priority
}
and while we're on the topic... we should support script-able access controls with a simple DSL for fine grain control:
MyModel.auth(function(ctx) {
if(ctx.is('admin') && ctx.is('owner')) {
return ctx.allow();
} else if(ctx.is('admin')) {
return ctx.deny('Hey... sorry buddy, you do not own ' + MyModel.modelName + ' ' + ctx.target.id);
} else {
return ctx.deny('Woah there... you gotta be an admin to use this API!');
}
});
Something that gives developers the ability to express logic easily. Sure it is not declarative, but it is simple to wrap your head around.
@crandmck any thoughts? Seems like an area of interest for you...
+1 on @ritch's proposal. I see roles as a shortcut in the JSON DSL.
I'm in the mode of getting rid of other principalTypes for ACL rules and keep role as the only option. We can always map different principal types into a role. The other consideration is to define protected resources to group model/operations to replace individual model/method/accessType. For example,
resources: {
shopping: [
{model: 'Order'},
{model: 'Catalog', methods: ['find', 'findById']}
]
},
acl: [
{
role: 'customer',
resource: 'shopping',
permission: 'ALLOW',
priority: '100' // explicit priority
}
]
Resources ...+Infinity... Really like that idea. Its also a natural mapping to oauth scopes.
@raymondfeng made one minor edit to your proposal: acls to acl
@ritch Sounds like an improvement on what we have now, from the stand point of ease-of-understanding and ease-of-explanation.
:+1:
+1 for multiple roles
Ya, great suggestion of multiple roles. But I have some more edit to this suggestion. which is can we put condition over role like && and ||. Actually I have a condition where I need the property to be accessed only if it's $authenticated && myCustomRole1 other wise deny. As putting only myCustomRole1 is not checking for authenticated i.e verify access token. May be I am not sequencing ACLs properly.
But in another scenario I'll need like allow only if myCustomRole2 || myCustomRole2 otherwise deny
is this achieved?
+1
+1
+1
hello ! :) is this achieved?
I am noticing a similar issue along the lines of the following. Granted that an array of roles isn't currently supported as proposed above take the following code for example:
{
"model": "merchant",
"accessType": "READ",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "DENY",
"property": ["find","findOne"]
},
{
"model": "merchant",
"accessType": "READ",
"principalType": "ROLE",
"principalId": "superprovider",
"permission": "ALLOW",
"property": ["find","findOne"]
},
{
"model": "merchant",
"accessType": "READ",
"principalType": "ROLE",
"principalId": "devtoken",
"permission": "ALLOW",
"property": ["find","findOne"]
},
In this case the role superprovider and devtoken are custom defined roles and in a particular request only superprovider is allowed access to the request.
PROBLEM
Despite superprovider being allowed access to the request because devtoken is not the request is denied altogether and swapping the allow objects for the two different roles does not fix the issue.
I was able to resolve the issue above after debugging with:
DEBUG=loopback:security:* npm start
However there still appears to be a seperate issue with regards to how custom roles are resolved.
I found that using a resolver that returns an error in the first paramater of the callback does not allow the ACLS to be searched. If I instead pass false as the second parameter and leave the first parameter undefined the ACLS are searched and superprovider is allowed for the request despite the rule for the devtoken which could be before or after the superprovider role. The ACLS are searched indicated by the following debug output:
loopback:security:acl The following ACLs were searched: +25ms
loopback:security:acl ---ACL--- +1ms
loopback:security:acl model merchant +0ms
loopback:security:acl property find +0ms
loopback:security:acl principalType ROLE +0ms
loopback:security:acl principalId superprovider +0ms
loopback:security:acl accessType READ +0ms
loopback:security:acl permission ALLOW +0ms
loopback:security:acl with score: +0ms 8148
loopback:security:acl ---ACL--- +0ms
loopback:security:acl model merchant +0ms
loopback:security:acl property find +0ms
loopback:security:acl principalType ROLE +0ms
loopback:security:acl principalId $everyone +0ms
loopback:security:acl accessType * +0ms
loopback:security:acl permission DENY +0ms
loopback:security:acl with score: +0ms 8007
loopback:security:acl ---Resolved--- +0ms
And If I swap the rules before the DENY rule I get the same order in which the ACL's were searched.
loopback:security:acl The following ACLs were searched: +3ms
loopback:security:acl ---ACL--- +0ms
loopback:security:acl model merchant +0ms
loopback:security:acl property find +0ms
loopback:security:acl principalType ROLE +0ms
loopback:security:acl principalId superprovider +0ms
loopback:security:acl accessType READ +0ms
loopback:security:acl permission ALLOW +0ms
loopback:security:acl with score: +1ms 8148
loopback:security:acl ---ACL--- +0ms
loopback:security:acl model merchant +0ms
loopback:security:acl property find +0ms
loopback:security:acl principalType ROLE +0ms
loopback:security:acl principalId $everyone +0ms
loopback:security:acl accessType * +0ms
loopback:security:acl permission DENY +0ms
loopback:security:acl with score: +11ms 8007
loopback:security:acl ---Resolved--- +0ms
But if I change the definition of the resolver function of devtoken from:
Role.registerResolver('devtoken', function(role, context, cb) {
if(parseInt(context.accessToken.userId) = -2) {
cb(null, false);
}
else
cb(null, true);
}
});
to
Role.registerResolver('devtoken', function(role, context, cb) {
if(parseInt(context.accessToken.userId) = -2) {
cb(new Error(), false);
}
else
cb(null, true);
}
});
The ACLS are not searched according to the absence of the debug output above. no indication of:
loopback:security:acl ---Resolved--- +0ms
And The request is denied despite the resolver for superprovider returning:
Role.registerResolver('superprovider', function(role, context, cb) {
cb(null, true);
});
This issue has been closed due to continued inactivity. Thank you for your understanding. If you believe this to be in error, please contact one of the code owners, listed in the CODEOWNERS file at the top-level of this repository.
+1
+1
In my opinion, this feature is really important and needs to be implemented directly or with some workaround. +1
Most helpful comment
Here's what I'd like to see:
and while we're on the topic... we should support script-able access controls with a simple DSL for fine grain control:
Something that gives developers the ability to express logic easily. Sure it is not declarative, but it is simple to wrap your head around.
@crandmck any thoughts? Seems like an area of interest for you...