-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Correct PrincipalType for multiple extension of User models #3823
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
Can one of the admins verify this patch? To accept patch and trigger a build add comment ".ok\W+to\W+test." |
|
@akki-ng thank you for the new version. I'll try to review your changes next week. |
|
@slnode ok to test |
| this.addPrincipal(Principal.USER, token.userId); | ||
| if (token.userId) { | ||
| const userPrincipalType = token.principalType || Principal.USER; | ||
| this.addPrincipal(userPrincipalType, token.userId); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I find this change suspicions - I would expect that token.principalType was already added on line 84 above.
Having said that, this change does fix certain bugs like e.g. #3829, so it's not without merit. I need to build a better understanding of this part of our codebase to be able to comprehend impacts of this change in a wider context.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Never mind, the line 84 was added back in 2013, before support for multiple user models were introduced. I suspect that code path was actually never used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bajtos You are right about line 84, but this block of code is neglecting the principal type associated with the accessToken,
loopback/lib/access-context.js
Lines 47 to 85 in 6ddf268
| context = context || {}; | |
| assert(context.registry, | |
| 'Application registry is mandatory in AccessContext but missing in provided context'); | |
| this.registry = context.registry; | |
| this.principals = context.principals || []; | |
| var model = context.model; | |
| model = ('string' === typeof model) ? this.registry.getModel(model) : model; | |
| this.model = model; | |
| this.modelName = model && model.modelName; | |
| this.modelId = context.id || context.modelId; | |
| this.property = context.property || AccessContext.ALL; | |
| this.method = context.method; | |
| this.sharedMethod = context.sharedMethod; | |
| this.sharedClass = this.sharedMethod && this.sharedMethod.sharedClass; | |
| if (this.sharedMethod) { | |
| this.methodNames = this.sharedMethod.aliases.concat([this.sharedMethod.name]); | |
| } else { | |
| this.methodNames = []; | |
| } | |
| if (this.sharedMethod) { | |
| this.accessType = this.model._getAccessTypeForMethod(this.sharedMethod); | |
| } | |
| this.accessType = context.accessType || AccessContext.ALL; | |
| assert(loopback.AccessToken, | |
| 'AccessToken model must be defined before AccessContext model'); | |
| this.accessToken = context.accessToken || loopback.AccessToken.ANONYMOUS; | |
| var principalType = context.principalType || Principal.USER; | |
| var principalId = context.principalId || undefined; | |
| var principalName = context.principalName || undefined; | |
| if (principalId != null) { | |
| this.addPrincipal(principalType, principalId, principalName); | |
| } |
I think we will need to correct the whole block for a holistic solution
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My initial thought is, if line 84 was supposed to set the correct principal type then line 47 is dumping the empty object in some corner case.
|
Related work: #3835 |
|
Hello @akki-ng, I am taking a look at your proposed changes. I started by trying to run your tests against the current master branch (see f774427) and they are passing for me! Does it mean the problem is already fixed? I suspect the change you are proposing in common/models/role.js may be still needed. How can I reproduce the bug which requires such fix? |
|
Hey @bajtos, the test cases were to pointout the problem of setting correct principalType in access context and allowing the user to be read correctly. If tests are passing then essentially we solved the problem of getting the user correctly from access context irrespective of their principalType. While the changes in role.js tries to solve a different problem but only specific use case. For ex, if we have many extensions of user model and other entities have only one belongsTo to any of custom user model, in that case $owner role was not working in ACL of those entities. The patch in role.js will allow users to use $owner in acls of a multi user environment considering if there is only one belongsTo relationship of a particular entity to any of custom user model to which $owner acl is specified. |
|
@bajtos to solve the use case of $owner not working in multi user environment, the patch wlon accessContext was mandatory. Now that accessContext patch is merged, you can reproduce the issue without the patch in role.js and confirm if applying the patch works properly. |
|
Closed by mistake, reopening now. |
|
Can one of the admins verify this patch? To accept patch and trigger a build add comment ".ok\W+to\W+test." |
|
@akki-ng thank you for the response.
We need to capture this in a test. Could you please explain little bit more the relation between different models, ideally as an example showing specific model names and the relations between them? I am happy to help you with writing the unit test, but I don't have bandwidth to research how to setup models and relations to trigger the problem. |
|
@bajtos thanks for writing the unit tests. I will create a sample app to demonstrate the issue by next day. |
That will be awesome! |
|
@bajtos Please follow the below example to understand why the code will fail in a corner case. For this example we have 2 custom user models (Seller and Customer), one Building model and one CustomAccessToken model to support polymorpic relations of token and users. Now follow the below steps in order to have the records ready
Set token of
Now set token of
Till now things worked as expected
Now make the changes in After making changes retry the API which were hanging when customer was loggedIn. The bug is if many extended user models are used and they have I hope this example will clear things up. Let me know if you are not able to reproduce. |
|
@akki-ng thank you for the instructions on how to reproduce the problem you are experiencing and sorry for the long delay! I was two weeks on a sick leave and my inbox exploded by the time I got back. I'll try to take a look at this in the next week or two. |
|
@bajtos Did you get the time to reproduce the issue? |
|
Not yet, sorry 😞 |
bajtos
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @akki-ng, thank you for the reproduction instructions and your patience with us.
I managed to reproduce the problem and have a fix coming shortly in a new pull request 🎉
| }else { | ||
| process.nextTick(function() { | ||
| callback(null, false); | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will not work in the following case: one user model owns another user mode, e.g. a Seller owns the business account of Customer.
|
Closing in favour of #3883 |
#3679
Patch is created along with the test case. Now access context will have the correct PrincipalType and
getUserwill work for all extensions ofUsermodel