-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Description
Hi friends,
There is a big problem. I've implemented a solution, but I think there have to be a real update from the loopback team. Here the case:
- There are 2 users, userA and userB. Both extend from the User model
- userA has a lot of rows with users already registered from 1 to n, and userB from 1 to m
- You loggin with userA, and you can do for example GET userAs/idGivenWhenLoggedIn and you will have an answer, but...
- You can also do GET userBs/idGivenWhenLoggedIn, without have logged in with userB. This issue is when both share the same userId, case it doesn't discriminate with the model used to log in, just the userId -> poblem.
This is very insecure, that can drive many developers that haven't found a solution yet, to make mistakes and maybe without realising.
The same thing is when it used the $owner and the $authenticate, etc. to create ACL rules. I implemented a solution to those cases, adding a custom "roleResolver", extending an accessTokenCustom model from the accessToken model, and adding the attribute "model" when some model logged in (the ones that extend from the User model). But those things, doesn't solve the initial problem, planted above.
One thing we can do is:
- Implement my solution + reset the ACLs (can that be possible?) + implement everything from scratch, without using the $authenticated and $owner roles
- Loopback developers, implement those changes, because it drives us to many errors that are hard to handle in small and, overall, big platforms.
The solution I comment above, is that (I wrote those lines in a general way):
- RoleResolver:
Role.registerResolver("customRole", function(role, context, cb) {
function reject(err) {
if(err) {
return cb(err);
}
cb(null, false);
}
if(!context.accessToken.userId) {
console.log("anonymous user is logged in");
return reject(); // do not allow anonymous users
}
if (context.accessToken.model == "Model") {
if (context.modelName == "Model")
{
if (context.modelId == context.accessToken.userId)
{
console.log("Model is logged in with id");
return cb(null, true);
}
}
else
{
console.log("Model is logged in");
return cb(null, true);
}
}
reject();
});
- ACL (is an example of the use)
{
"accessType": "*",
"principalType": "ROLE",
"principalId": "customRole",
"permission": "ALLOW"
}
- AccessTokenCustom (model based in AccessToken)
{
"name": "AccessTokenCustom",
"base": "AccessToken",
"idInjection": true,
"options": {
"validateUpsert": true
}
-
Replace accessTokens relations in models extended from the User model:
"relations": { "accessTokens": { "type": "hasMany", "model": "AccessTokenCustom", "foreignKey": "userId" } } -
Finally, fill the model attribute when a user log in:
userExtendedFromUserModel.prototype.createAccessToken = function(ttl, options, cb) {
if (cb === undefined && typeof options === "function") {
// createAccessToken(ttl, cb)
cb = options;
options = undefined;
}
cb = cb || utils.createPromiseCallback();
if (typeof ttl === "object" && !options) {
// createAccessToken(options, cb)
options = ttl;
ttl = options.ttl;
}
options = options || {};
var userModel = this.constructor;
ttl = Math.min(ttl || userModel.settings.ttl, userModel.settings.maxTTL);
this.accessTokens.create({
ttl: ttl,
model: userModel.modelName
}, cb);
return cb.promise;
};
This solution that I created with the help of some answers, most of them from this issues, is not enough. We really need something powerful, something from the root. In this moment I'm working in a project and I need to find a elegant way to do these things.
That solution doesn't solve the problem I presented above. Maybe it could be solved using a extended User model without inherit its ACL rules and the solution commented. Supposing this case, there is some way to extend a model from a base model without inherit its ACL rules? If the answer is yes, I really appreciate know "how" (for now), otherwise what can I do to solve the main problem?
For now, I suggest (from your side, the loopback team):
- Add the "Model Name" as a column in the AccessToken, that would be very useful to implement custom role resolvers and also to not modifying the prototype method (is not a good idea do that)
- Enable the model option to reset the ACL rules when you extend from a model.
With both, is possible to implement better solutions using loopback. I believe there are better ones rather than mine, but ok, it's a good point to start with, and are not very complex to implement in a release (soon please, I really need it).
I'd really appreciate your help.
Thanks,
Sebastián.