Problem/Motivation
- Private image fields on taxonomy term pages always return a 403.
Steps to reproduce
- Log in as user 1.
- Enable a private files directory.
- Create a vocabulary.
- Add an image field to the vocabulary that uses the private files directory.
- Add a term to the vocabulary and upload an image for the term.
- Visit the term page.
Expected result
The image is visible on the term page.
Actual result
The image returns a 403.
Proposed resolution
- TBD
Remaining tasks
- TBD
User interface changes
- TBD
API changes
- TBD
Original report by johnv
I reported this earlier as a D7.0 error in #846296: file_file_download() only implements access checks for nodes and users. This page now generates a 'Access denied', so i presumed it was fixed as a security issue. However, the error still exists on D7.9.
This is how to create the issue:
- create a vocabulary, and add an image field. The field uses the private file system;
- add terms;
-- under manage fields, add an image using the private file system;
-- under manage display, set to Image and use a Image style;
- create a Views display showing terms. Include an Image field from the term.
- show the Views display: for each image to be displayed, the following warning is generated and the image is not shown:
TYPE access denied
LOCATION http://example.com:8082/system/files/styles/thumbnail/private/tpm/my_ima...
MESSAGE system/files/styles/thumbnail/private/tpm/my_image.jpg
- show the default Term page: idem
Attached patch fixes the issue.
| Comment | File | Size | Author |
|---|---|---|---|
| #81 | 1327224-81.patch | 3.41 KB | poker10 |
| #81 | 1327224-81_test-only.patch | 2.89 KB | poker10 |
| #80 | After_patch_error.png | 562.97 KB | vikashsoni |
| #80 | before_patch_image.png | 11.85 KB | vikashsoni |
| #79 | taxonomy-term-file-download-access-d7-1327224-79.patch | 3.41 KB | bkosborne |
Comments
Comment #1
johnvComment #3
johnvpatch without spaces in name?
Comment #4
johnvComment #6
xjmThanks for the patch! In order for testbot to test it, it should be created with git. See: http://drupal.org/patch/create
Tagging as novice for creating a new patch.
We should also add tests for this. Should be simple enough: Try to access a term, and if it can be accessed, assert that a file attached to it can also be accessed.
Comment #7
chris.leversuch commentedHere's a git version of the patch. I wasn't sure if it needed to go in a specific place in the file so I've just put the code at the end.
I'll need to read up on writing tests if they need to be in the same patch.
Comment #8
damien tournoud commentedThis explanation doesn't make any sense. This type of logic should already be handled by the default access control on files.
Comment #9
xjmAs I recall, this was related to SA-CORE-2011-001.
Comment #10
johnvThe patch is over a year old. And now that I have doubled my Drupal-experience :-) , I am not sure if granting such a permission is the best idea. The file is now public for everyone....
Anyway, the behaviour for Term image is different from that of Node images.
Comment #11
chris.leversuch commentedI just picked up the issue from the novice queue. Is the issue still valid or should it just be closed?
Comment #12
johnv@chris, I didn't realize you just popped in, thanks for the new patch.
The issue is still valid (at least for me - I would expect more people having this problem), but i doubt this is the best solution.
I have also edited the original post for more clarity.
Comment #12.0
johnvBetter explanation of the case.
Comment #13
xjmI agree that blithely returning
TRUEis not the correct solution.The steps to reproduce in the summary make it sound like you need views to reproduce this issue, but it is reproducible without views.
Expected result
The image is visible on the term page.
Actual result
The image returns a 403.
Comment #13.0
xjmbetter explanation.
Comment #13.1
xjmUpdated issue summary.
Comment #13.2
xjmUpdated issue summary.
Comment #13.3
xjmCorrection.
Comment #14
ZenDoodles commentedZgear will write tests. :)
Comment #15
xjmComment #16
edb commentedI think the only access control we can use for this that makes sense is field_access. Patch is attached, thoughts?
Comment #17
nyirocsaba commentedLooks like the entity_type isn't a string, it's the entity object instead.
Comment #18
ryan.ryan commentedComment #19
ryan.ryan commentedRerolling patch
working on tests.
Comment #21
ryan.ryan commentedActually, while dags and I were working on the tests, we realized that the patch actually doesn't work anymore.
Before and after applying the patch I get the same results. I get a 403 when trying to view the term's image.
Good news is the test is pretty much done when this gets fixed again! :)
Comment #22
berdirThis hook has changed, the arguments passed in are now $field, $entity, $file, see file.api.php for an example.
It's then $entity->entityType() to get the entity type and that's also what you need to pass to field_access().
Comment #23
berdirAlso, as mentioned in IRC, we have an entity access system now, so file.module by default could check $entity->access('view') once the issues mentioned in #1696660-117: Add an entity access API for single entity access are fixed. That would remove the need for custom hook implementations for every single entity type (user might have this problem too?)
Tests are still useful, though.
Comment #24
ryan.ryan commentedAlright, keeping this as needs work and unassigning myself. Dags and I will keep working on the tests.
Comment #25
berdirThis patch shows what I've been talking about. It should fail for the moment, but pass once the mentioned issues are fixed.
We can simplify it even further maybe, not sure if we still need two hooks there.
Comment #27
ryan.ryan commentedAlright, so I am not finished but wanted to post this before I forget. We've started the test but are def not finished. Here's what we've got so far.
Comment #28
berdirtypo...
Comment #29
berdirOk, I think we can actually go considerably further here.
Given that we have a unified entity and field access system, I do not see a use case for even needing these hooks at all anymore.
If someone has access to the entity and access to the field, he has access to the file.
Also merged in the test code from #27.
Comment #31
berdirOk, here we go.
Worked on the test that now actually passes because the term access issue went in. Removing the needs test tag and the novice tag as writing that test wasn't that easy :)
Attaching the full patch, test only patch and interdiff.
This *should* pass once node access issue is in, we'll see.
Comment #32
johnvWow, a patch that adds functionality by removing code!
Comment #34
berdirSomething else to consider is that file entities should have an access controller too. And I think we should move the entity/field check into an viewAccess() implementation for the file entity. What I'm not yet sure is how the field type argument will be handled.
@davereid also mentioned a download access check for files instead of view but I'm not sure if I see a need to differentiate between view and download. Comes back to my main argument in this issue, that we don't need a separate download check if we can check view for the entity/field combination.
Comment #35
berdir#31: file-download-access-1327224-31.patch queued for re-testing.
Comment #36
berdir#31: file-download-access-1327224-31-test-only.patch queued for re-testing.
Comment #37
berdirTagging.
Comment #39
berdirOne test fail remaining because comments are not yet converted: #1862754: Implement entity access API for comments
Comment #40
berdirTagging.
Comment #41
berdir#31: file-download-access-1327224-31.patch queued for re-testing.
Comment #42
berdirFixed the node related test, taking over the fix from #1947880: Replace node_access() by $entity->access().
Comments are mean, not sure why I didn't notice that before.
viewAccess() in CommentAccessController just does user_access('access comments'), the removed comment hook here does a lot more. it checks comment status/admin permission, which viewAccess() should absolutely do as well.
The problematic part is that it also checks access to the node, which makes sense as well, but would be a considerable overhead to do in viewAccess(). So.. I'm not sure what to do. Have a special operation for download that defaults to view but entities can override it? That will actually mean that we're back at allowing entities to easily customize download access but making it optional. Which sounds like win-win to me :)
Comment #44
andypostThis needs update the summary. Not sure that mix of field-level settings and entity_view is good default without alter.
Why the file entity access not involved here?
Seems very questionable!
But what's about file entity access?
Comment #45
berdirfile entity access is not involved because this is the file entity access *implementation*, it's just not yet within an access controller. For example because there's contextual information (field_type) that is not accessible from within an access controller without doing some ugly tricks.
Here's a re-roll that uses the new flexibility of the access controllers to introduce a new download operation that entities can implement if they want to. I do have to change the default implementation to make NULL a valid return value, so that I can separate between "not implemented" and "denied.
@fubhy, what do you think about that change?
Comment #46
dave reidHaving entities aside from files that have a download operation, just doesn't smell right. Having the comment view access operation not check node access by default doesn't smell right.
Comment #47
berdirThis is an implementation that improved the comment view access operation to the point where all this stuff isn't necessary.
If that's not a performance issue then that's fine with me as well. It shouldn't be, because for the typical case, we are only checking comments of a single node so we are hitting the static caches for both the entity load and access checks. A different case would be comments across multiple nodes on a single page.
Comment #49
berdirRefactored the taxonomy image test to avoid #1957888: Exception when a field is empty on programmatic creation.
Comment #51
berdir#49: file-download-access-1327224-49.patch queued for re-testing.
Comment #52
andypostSuppose this change out of scope, let's fix it after #731724: Convert comment settings into a field to make them work with CMI and non-node entities
It's not clear why user with rights to admin comments should depend on access to node?
Comment #53
berdir#49: file-download-access-1327224-49.patch queued for re-testing.
Comment #55
berdirYeah, that didn't work out :(
Here's a limited patch that just adds the test and a hook implementation for terms. Opened #2078473: Use entity access API for checking access to private files to look into improving the API.
Comment #57
berdirOk, fixed the test, was written a long time ago ;)
Comment #59
berdirFailed/Passed as expected, test-only behavior is really broken :(
Comment #60
andypostJust a small nitpicks
no langcode now
space after $edit
Comment #61
berdirThanks, fixed.
Comment #63
andypostA new set of nitpicks
Is this need @var?
drupalPostForm() & vocabulary->id()
Comment #64
berdirYeah, the drupalPost isn't really a nitpick but other than that, I hope you're running out of nitpicks soon :)
Comment #65
andypostIt's now ;) no more nitpicks
Comment #66
alexpottCommitted 820205f and pushed to 8.x. Thanks!
Unnecessary use statement removed during commit.
Comment #67
johnvAs OP I'd like to thank you for your work!
Comment #68.0
(not verified) commentedUpdated issue summary.
Comment #69
berdirI think we forgot to backport this.
Comment #70
bnjmnmWorking on 7.x backport
Comment #71
David_Rothstein commentedThis issue is closely related to #2305017: Regression: Files or images attached to certain core and non-core entities are lost when the entity is edited and saved, which is a critical regression. Looking for any feedback there on how to fix it...
Comment #72
bnjmnmComment #75
peterpoe commentedThose needing a quick fix on Drupal 7 may implement this hook in a custom module:
Comment #76
peterpoe commentedSorry, double submit.
Comment #79
bkosborneHere the patch from D7 with tests (tests were easily ported from D8 thankfully)!
The access control should be handled by 'access content' which is what already controls access to viewing a term. This is also what D8 does.
Comment #80
vikashsoni commentedpatch applied successfully after the patch i am able to access image sharing screenshot ...
Comment #81
poker10 commentedI think the patch in #79 looks good. Reuploading the same patch with test only version to verify that failures are present. Anyway if the testbot does not show any problems, this should be RTBC (has test, backport, verified with manual testing).
Comment #83
poker10 commentedPatch #79 verified, switching to RTBC.
Comment #84
mcdruid commentedPatch looks good and excellent to have the backported tests.
Is this likely to break existing functionality or just fix the OP's bug?
Trying to decide if it needs a Change Record; I think that would only be necessary if we think sites might be relying on the existing functionality (or lack thereof) in some way.
Comment #85
poker10 commentedI think we can add a Change record, because this patch is changing the default behavior from access denied to everyone to allow access to everyone (with access content permission / access to taxonomy terms by default), though it is a bug. Maybe some sites were using this broken behavior, but I do not see any reasonable use for it.
But according to the description of
hook_file_download_access()(see: https://api.drupal.org/api/drupal/modules%21file%21file.api.php/function/hook_file_download_access/7.x):So we are basically setting TRUE for all (with access content permission / access to taxonomy terms by default), so if there are some contrib/custom modules setting this more precisely now (using this concrete hook), we will override them (but hopefully most of them are using the alter version of this hook correctly). These modules would need to be updated to use the hook_file_download_access_alter(). Taking into account this possibility I think we should add the Change record.
Comment #86
poker10 commentedHere is a draft of the proposed change record: https://www.drupal.org/node/3307802
Comment #88
mcdruid commentedThanks everyone!