I've created a model Webuser based on the built in User model.
This is this model's ACL entry in "webuser.json":
"acls": [
{
"accessType": "*",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "DENY"
}
]
To my surprise, I can login via POST /api/webusers/login with no problems. I expected all access to be denied.
What am I doing wrong?
Well I believe the default user acls are still working and they are not overrided. The way loopback decides which ACL entry is effective for the request, is by selecting most specific one that appears later. So loopback has defined this entry:
{
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "ALLOW",
"property": "login"
}
Since it's as specific as it gets, to beat that you have to add this in your model:
{
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "DENY",
"property": "login"
}
There's also another way to remove the default user acls via code but it's not documented.
Related
i m try to implement acl for model(named as company)
"relations": {
"user": {
"type": "belongsTo",
"model": "user",
"foreignKey": "company_id"
}
},
"acls": [
{
"accessType": "*",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "DENY"
},
{
"accessType": "*",
"principalType": "ROLE",
"principalId": "$owner",
"permission": "ALLOW"
}
],
deny all user and access only to authenticated user owner of that object . here i m also try to add permission for super user who have all permission in short admin and owner of objec(data) can do crud is there any soultion for this please help
You can deny all unauthenticated users then deny everyone and allow only the owner like below :
{
"accessType": "*",
"principalType": "ROLE",
"principalId": "$unauthenticated",
"permission": "DENY"
},
{
"accessType": "*",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "DENY"
},
{
"accessType": "*",
"principalType": "ROLE",
"principalId": "$owner",
"permission": "ALLOW"
}
you need only CRUD for the $owner, you can assign the properties needed for your user as below :
{
"accessType": "*",
"principalType": "ROLE",
"principalId": "$owner",
"permission": "ALLOW",
"property": [
"find",
"create",
"updateAll",
"delete"
]
}
For the super user you should create this Role and assign it to one of your users.
{
"accessType": "*",
"principalType": "ROLE",
"principalId": "superuser",
"permission": "ALLOW"
}
How to create a ROLE ? you can follow the documentation here.
And make sure that you have this file /server/boot/autentication.jsand authetication is enabled : server.enableAuth()
'use strict';
module.exports = function enableAuthentication(server) {
// enable authentication
server.enableAuth();
};
For more ACL tricks please read the official documentation here.
I have a user which own a house (several of users can own the house), the house can have several of furnitures.
CustomUser.json relation:
"houses": {
"type": "hasAndBelongsToMany",
"model": "House",
"foreignKey": "houseId"
}
House.json relations:
"furnitures": {
"type": "hasAndBelongsToMany",
"model": "Furniture",
"foreignKey": ""
},
"customUsers": {
"type": "hasAndBelongsToMany",
"model": "CustomUser",
"foreignKey": ""
}
My ACL is simple and looks like this for both House and Furniture:
"acls": [
{
"accessType": "*",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "DENY"
},
{
"accessType": "*",
"principalType": "ROLE",
"principalId": "admin",
"permission": "ALLOW"
},
{
"accessType": "*",
"principalType": "ROLE",
"principalId": "$owner",
"permission": "ALLOW"
}
]
Now, accessing houses for the users works fine, but the users won't get their furnitures listed since they belong to a house (the house is the owner). How do I fix this the easiest way possible? Best would be to somehow define that User owns furnitures through the house? The furnitures must belong to the house, though (since multiple users can have a house).
So I got past this through another module called "loopback-component-access-groups" which lets you define groups. In this particular case I made the House-model a group which the users and furnitures have access to. A user can have different roles so I just set that the user (which have the role "member") can access the furnitures which are in the same group (house). This solution works for me, but I am not entirely sure if further objects inherits that they belong to a house if they are related to a furniture.
Writing my own role resolver made this quite flexible, in the role resolver I had to make logic to find the original parent and also make sure there were no dead relationships (since LB doesn't have support for cascade yet).
I recommend starting with this to get going:
https://loopback.io/doc/en/lb3/Defining-and-using-roles.html
I'm using ACL rules to block all types of accesses from all the users. It is working for GET access but it is NOT working for POST accesses.
Any idea what could be wrong?
Here is the code and sample results:
/common/models/client.json
{
"name": "client",
"plural": "clients",
"base": "User",
"idInjection": true,
"properties": {},
"validations": [],
"relations": {},
"acls": [
{
"accessType": "*",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "DENY"
}
],
"methods": {}
}
GET access error (working as expected, it is blocked):
CURL
curl -X GET --header "Accept: application/json" "http://localserver:8080/api/quants"
RESPONSE
{
"error": {
"name": "Error",
"status": 401,
"message": "Authorization Required",
"statusCode": 401,
"code": "AUTHORIZATION_REQUIRED",
"stack": "Error: Authorization Required\n at ...
}
}
POST error, access didnt get blocked. Not working.
CURL:
curl -X POST --header "Content-Type: application/json" --header "Accept: application/json" -d "{
\"email\": \"test#email.com\",
\"password\": \"abcd1234\"
}
" "http://localserver:8080/api/clients"
RESPONSE
{
"email": "test#email.com",
"id": "46b258078da5dtg1ji5809ww"
}
Before suggesting solutions, I'll try to explain what's the cause of 'create' (POST) method to not be denied.
Your client model is a sub-model of Loopback's User built in model.
Two important things to keep in mind in this case:
ACL's defined in a sub-model are not overriding the base class ACL's, but merged to them.
When a request is checked against ACLs, Loopback's algorithm gives the closer match higher weight. closer match in this specific case is a more specific ACL definition. (reference here)
Now, Loopback's User model contains the following ACL:
{
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "ALLOW",
"property": "create"
}
Your defined ACL
{
"accessType": "*",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "DENY"
// no specific property
}
is less specific, hence not chosen by the algorithm.
In order to solve the issue, you can:
Add specific ACL for denying creation:
{
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "DENY",
"property": "create"
}
Remove the ACL allowing to create from the base User model (very bad solution, but works)
I want to define a set of ACL rules that should be easily portable and extendable by using mixins.
Defining these in the MyModel.json for some model MyModel is trivial:
"acls": [
{
"accessType": "*",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "DENY"
}]
This works, and correctly blocks API calls for everyone. However, when I do the same thing (or so I think) in a mixin, it does not work:
module.exports = function (Model, options) {
Model.getApp(function (err, app) {
app.models.ACL.create({
model: Model.modelName,
accessType: '*',
principalType: 'ROLE',
principalId: '$everyone',
permission: 'DENY'
}, function (err, acl) {
console.log('ACL entry created: %j', acl);
});
});
};
What is missing?
After going through the sources to see how Loopback itself registers ACL at config time, the following appears to be the correct way of doing this in a mixin:
module.exports = function (Model, options) {
Model.settings.acls.push({
"accessType": "*",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "DENY"
});
};
I have typed in at the commandline: slc loopback:acl
and disabled all security for the User model.
Going into strongloop explorer, doing a simple GET Users request gives me a 401 authorization required error.
Any ideas how to open up the User object? Is this a known bug?
Thank you
You can extend your user model and set permissions for your custom model like this:
{
"name": "CustomUser",
"base": "User",
"idInjection": true,
"properties": {},
"validations": [],
"relations": {},
"acls": [
{
"accessType": "READ",
"principalType": "ROLE",
"principalId": "$unauthenticated",
"permission": "ALLOW"
},
{
"accessType": "READ",
"principalType": "ROLE",
"principalId": "$authenticated",
"permission": "ALLOW"
},
{
"accessType": "*",
"principalType": "ROLE",
"principalId": "$owner",
"permission": "ALLOW"
}
],
"methods": []
}
However I would NEVER recommend you doing this.
If you really want to disable the endpoints on the User model, you can do this.
Go to your model.config.json and add "public": false to the User field like so:
...
"User": {
"public": false,
"dataSource": "db"
},
...