Subissue of #2028027: [META] Missing access control for base fields
Fields needing access control:
- password
- status
- init
- access
- login
| Comment | File | Size | Author |
|---|---|---|---|
| #70 | interdiff.txt | 3.24 KB | pfrenssen |
| #70 | 2029855-70.patch | 14.68 KB | pfrenssen |
Subissue of #2028027: [META] Missing access control for base fields
Fields needing access control:
| Comment | File | Size | Author |
|---|---|---|---|
| #70 | interdiff.txt | 3.24 KB | pfrenssen |
| #70 | 2029855-70.patch | 14.68 KB | pfrenssen |
Comments
Comment #1
fagoThanks! I'm re-title the issue a bit to be consistent with the other.
So this issue is for implementing default access for all base fields of a user. We need to go through them and look for existing access restrictions and make sure they are covered as part of the default Access of their field's item classes.
Example: We've got a permission for editing user names, that needs to be covered.
What to do: For each field that has a default access being not TRUE, we
- have to add a custom FieldItem class extending the field type's one
- implement defaultAccess() for it
- write a unit test case to prove it works as it should
Note: The list of fields we have to care have doesn't seem to be complete (I've not checked either), at least user name is missing.
Comment #2
fagoComment #3
fgmComment #4
fgmFirst step, just to show where this is going, get comments, and see if it breaks something: implement the default access for the user name base field.
Comment #5
fgmNow with unit tests.
Comment #7
fgmThe same test passes locally with the rerolled patch over the most recent commits. Manually performing the test also works as it should, so retrying with rerolled patch.
Comment #8
fagoShould be Contains and have a new line before the docblock
Summary should not exceed one line, i.e. a line break and a new line after the first sentence.
I don'T think we need to document this here as that's the case for every field item list.
Should just return TRUE as discussed.
Either use $return as variable name or just return it directly.
HAving all those ops here does not make sense. Let's revisit this once we've figured $ops out at #1994140: Unify entity field access and Field API access.
I'd say the user name field has custom access rules.
Comment #9
fgmRerolled accordingly. Adding another one while the bot tests.
Comment #10
fgmJust noticed a typo in the file-level phpdoc. Will include in the next version of the patch.
Comment #11
fgmNew version. This refactors logic and provides access for most base fields:
There are probably policy decisions to be made regarding them, though, because for most of those we didn't have clear access policies regarding them until now.
Remaining to implement:
It also makes the
$accountparameter onFieldItemList::defaultAccess()non-optional, as seen with yched and fago.Comment #11.0
fgmUpdated issue summary.
Comment #12
jibran11: 2029855-default_user_field_access-11.patch queued for re-testing.
Comment #14
benjy commentedJust a straight re-roll, there were a few conflicts so see what the bot says.
Comment #16
benjy commentedFieldItemList had moved.
Comment #18
benjy commentedFieldItemListInterface had also changed. This time I tested the installer so hopefully we can get past that.
Comment #19
andypostJust docs gate and small nitpicks
should be full namespace
needs description of return walue
needs fix
trailing space
needs empty line
Comment #20
catchComment #21
benjy commentedDoc stuff from #19 fixed plus a few extras.
Comment #23
benjy commented21: 2029855_20.patch queued for re-testing.
Comment #24
benjy commentedComment #25
klausiklausi opened a new pull request for this issue.
Comment #26
klausiNew approach: use a checkFieldAccess() method on the access controller same as for entity level access which uses checkAccess(). That way we can easily specify reasonable field access defaults without hacking/overriding all the field item classes. And you have field access in one place.
Comment #27
moshe weitzman commentedThis looks really simple and clear.
I noticed that we remove password field in user_template_preprocess_default_variables_alter(). Is there now a better way to do that?
Comment #28
fgmUnassigning myself: not working on this at the moment.
Comment #29
berdirWhile much faster, DUBT and especially EntityUnitTestBase still isn't as fast as a unit test, wondering if it's worth to use a single test method + doSomething() methods pattern here, but running the test took 3 seconds for me, so not worth it.
This seems very indirect, why not just pass the thing that should be access-checked into the helper method? If you want something to display for the message then you could use the username/label() for that?
Comment #30
klausiklausi pushed some commits to the pull request.
For an interdiff please see the list of recent commits.
Comment #31
klausiCombined the test methods in one for performance, interdiff: https://github.com/klausi/drupal/commit/b96605cdd2e2b3834ec28170d58e1a7f...
I don't want to change the invocation of the assertion because I think it is easier to read and understand in the current form, where looping and actual user accounts get out of the way as much as possible.
Comment #32
klausiklausi pushed some commits to the pull request.
For an interdiff please see the list of recent commits.
Comment #33
klausiklausi pushed some commits to the pull request.
For an interdiff please see the list of recent commits.
Comment #34
klausiNow completely converted the test case to phpunit, removing one more frankenstein drupal unit test we should not use anymore.
dawehner said that we might want to group the field access method by operation, but I'm not sure about that. It would make the implementation even longer.
Comment #35
fagoYeah, I think the method is ok as it is. It's not nice looking, but the best I can think of.
Should start with (optional)
Should be consistent, i.e. always use the direct return of the comparison result.
Comment #36
klausiklausi pushed some commits to the pull request.
For an interdiff please see the list of recent commits.
Comment #37
klausiActually $account is not optional in that case, so I fixed the comment. Also fixed the comparison return logic for the created date. Interdiff: https://github.com/klausi/drupal/commit/1558228422dd2051dd912acece2284a5...
Comment #38
fagoPatch looks decent now, only found the following:
Maybe we should add a paragraph documenting when this is taken into account and when not.
I do not think the comma here is needed.
Besides that, this needs a review of whether the access implementation for user is correct. (I've not reviewed this part yet).
Comment #39
berdirChanging roles needs "administer permissions", check AccountFormController, so we should check that first.
I'm also not sure if editing some fields like init/access/login should be prevent, as you wouldn't want that to be allowed over rest?
We discussed this, and while kind of correct as we rely on entity level edit access, this still reads very weird. Not sure what to do about it.
Comment #40
kim.pepperTaking a look.
Comment #41
kim.pepperI tried to understand the comments in #38 and #39, but instead just did a simple re-roll of #36 including the PSR4 changes.
Comment #43
kim.pepperThat re-roll was missing UserAccessController.php
Here goes again.
Comment #44
xjmComment #45
xjmComment #46
berdirAs mentioned in the call, this is not specific to rest.module, that's just one usage of this API. Another are field widgets/formatters, and the patches that are converting the custom form code there to widgets need to keep the custom access control right now, see patches and discussion in #2227381: Apply formatters and widgets to User base fields 'name' and 'email' as an example.
Those hacks only work in the normal form, if you add quickedit.module which directly edits a field using its widget, it will not get the correct access and would allow you to edit something that you aren't allowed to do, like being able to edit the username if you don't have the permisison to change the username.
Comment #47
tstoecklerWhich also means administrators can view the 'password' field. Is that wanted?
Comment #48
berdirYeah, another issue :) Agreed that should be limited as well.
The tests pass but that's only because they were written to match the implementation.
Comment #49
hussainwebI am attaching a patch to fix the problem in #47. I understand we should update the test cases as well. Let's see how this patch goes.
Comment #50
berdirPlease provide an interdiff when making changes to a patch, it's very hard to see what exactly you changed otherwise.
We need to to something similar to roles and there's also some other possible cleanup necessary, see #38 and #39.
Comment #51
kim.pepperI created an interdiff from the last 2 patches.
Comment #52
berdirI'm a bit lost at how to get this correct and verified, probably picked the hardest example to get the API in.
Therefore, I updated the patch in #2098355: Missing default access for all node fields so that we can get the API in an issue where the implementation is not as complex. Please help to review that.
Comment #53
berdirSee #2028027: [META] Missing access control for base fields, while this is still a critical security bug, it is IMHO no longer a beta target as we have the API in place, we just need to implement it.
Comment #56
hussainwebAttempting to reroll. I will review all the comments after this patch goes.
Comment #58
hussainwebIt seems changes in
EntityAccessControlHandler.phpare no longer required (as hinted in #53). This is basically still from the reroll (as the reroll resulted in PHP errors). The interdiff wouldn't really give a clear picture here. The patch now contains changes only in user module.Comment #60
hussainwebTrying again. Moving test file in correct location and changing the namespace to match.
Comment #62
berdirThis needs to return AccessResult objects now, see how NodeAccessControlHandler works now.
Comment #63
star-szrI can at least do a reroll but I will try to address #62 as well.
Comment #64
star-szrLet's try this.
Reroll, revised patch, and interdiff attached.
Comment #65
berdirThanks!
This unfortunately doesn't work like this.
Field access is allowed by default and allowedIf() is a allowedIfOrIgnore(), and not a allowedIfOrForbidden(), so this will never deny access.
You need to do $condition ? ::allowed() : ::forbidden() here.
Comment #66
star-szrAh, got it. I can take care of that.
Comment #67
star-szrThis should be better. I'm not sure if I'm doing things correctly for the caching.
This also would suggest that we're missing test coverage, right?
Comment #68
pfrenssenComment #69
pfrenssenLooked at this briefly. There was a problem with the test data providers not returning the full set of test data. I still have to test this locally, but have to attend a meeting now.
Leaving this assigned to me for the moment, will have another look tomorrow.
Comment #70
pfrenssenThere was indeed missing coverage: the case of an owner viewing or editing its own email address was not covered, causing the bug that was fixed in #67 to be undetected. I did a code coverage analysis and this indicated that the default case was also not covered.
Added all missing test coverage and put some more documentation since I was bewildered to see a test of an anonymous user not being able to view a field on a user but seemingly being able to edit it. I'm not sure if this comment is factually correct, so it would be nice if someone can confirm this:
Comment #73
berdirThat fail there was HEAD failing.
Comment #74
moshe weitzman commentedHoly exhaustive tests!
Comment #75
alexpottCommitted 59788e3 and pushed to 8.0.x. Thanks!
Fixed spelling mistakes on commit.