Problem/Motivation
One of the biggest challenges of the File entity module is providing a more fine-grained access control API for different actions like viewing, downloading, editing, etc. Currently, Drupal core only provides one access API via hook_file_download() which is not compatible with the File entity access API because it assumes that the file is not an entity. This hook is even more fun because it has two purposes: check access to download a file, and return all the headers that should be sent if the file can be downloaded. In addition, this hook is very limited; you cannot check if another user has access to download a file, you can only check if the current user has access.
Proposed resolution
Extend EntityAccessController for use with file entities.
Remaining tasks
- Make a new hook to replace the 'Provide download headers for this file' functionality of hook_file_download()
User interface changes
None
API changes
Add hook_file_download_headers()
Will need a change notice for hook_file_download().
Comment | File | Size | Author |
---|---|---|---|
#60 | interdiff_59-60.txt | 401 bytes | immaculatexavier |
#60 | 2148353-60.patch | 13.55 KB | immaculatexavier |
#59 | 2148353-59.patch | 13.68 KB | quietone |
#59 | diff-45-59.txt | 9.32 KB | quietone |
#45 | 2148353-45.patch | 14.2 KB | marthinal |
Comments
Comment #1
tim.plunkettOne thing that doesn't quite fit neatly into any of the tasks above:
To deny access completely, an implementation would return -1, and then all three invokers call
throw new AccessDeniedHttpException();
.Should the hook just throw that themselves? would that remain part of new hook, or become part of the entity access?
Comment #2
Dave ReidNot quite sure I understand. I would want this system to work exactly like node access does, without the grant system.
Comment #3
tim.plunkettI misunderstood how the headers were defined. In all core implementations, the headers for an accessible file are always the same, it is not tied to any of the access logic. +1 to the proposal.
Comment #4
larowlanAny objections if I take a run at this?
Comment #5
larowlanAdded #2128791: File resource needs an access controller to related
Comment #6
larowlanDuplicate of #2078473: Use entity access API for checking access to private files
See also #1327224: Access denied to taxonomy term image
Comment #7
Dave ReidThis has way more detailed plans on how to replace private file access. We should have at least transfered that knowledge and plan before closing this.
Comment #8
BerdirThe main reason I haven't been successful with this is that file exists has the special-flower $field_type context and is only called and checked for files referenced via a given field_type. If we can drop that, great, I have no idea why we need it exactly.
Not sure with download vs view, why do we need two different operations for that? The way core works is that it respects field access view if explicitly provided in the file download access hook. I can see a case where you want to display the field but then not actually allow download access. However, core has no way to do that, as we would need a way to disable the link or redirect to another page to do that in a way that makes sense.
Also, the two issues *are* different. This is about moving the logic here into a access controller, while the other is about changing the logic and instead of using custom hook, replace it by using the existing entity access API. Can be combined into one issue, though.
Comment #9
ParisLiakos CreditAttribution: ParisLiakos commented+1 for dropping $field_type parameter
download vs view: i think core shouldn't be bothered by it and treat it the same..ie view. i can think of some use cases, but those could easily just be in contrib.
Comment #10
blueminds CreditAttribution: blueminds commentedAddressed in #2078473: Use entity access API for checking access to private files
Comment #11
ParisLiakos CreditAttribution: ParisLiakos commentedtbh, i like this issue's summary more
Comment #12
Dave ReidPlease *do not close this again*. #2078473: Use entity access API for checking access to private files is for removing hook_file_download_access(). This issue is for removing hook_file_download().
Comment #13
Berdir#438414: hook_file_download() should pass $file objects rather than $filepath
4 years later ;)
Comment #14
slashrsm CreditAttribution: slashrsm commentedShould we postpone this until #2078473: Use entity access API for checking access to private files goes in?
Comment #15
XanoThat was *just* fixed, so postponing this issue is no longer necessary :)
Comment #16
ParisLiakos CreditAttribution: ParisLiakos commentedi did a start on this, tests will fail, but maybe someone can drive this till i have some time
Comment #18
blueminds CreditAttribution: blueminds commentedWill take a look at those tests.
Comment #19
blueminds CreditAttribution: blueminds commentedFollowing things have been done:
- File entity now has getContentHeaders() method that replaced file_get_content_headers()
- all the access logic moved to the FileAccessController, therefore file_file_download(_headers) was removed
- image_file_download(_headers) was removed as the logic is now in the ImageStyleDownloadController::deliver()
- hook_unmanaged_file_download_headers() was introduced to be able to add headers to unmanaged files.
So currently there is no hook that would deal with headers for a managed download file. But consulted this with @slashsrm and @Berdir and they confirmed that there has never been a usecase that needed to alter/add headers. However if that is the case the KernelEvents::RESPONSE can be used to do so.
Let's see what the testbot has and others have to say about this, then the issue summary probably will need to be updated and also a change record will be needed.
Comment #21
blueminds CreditAttribution: blueminds commentedFixing tests
Comment #22
BerdirWe should rename the key here I think, this matches the hook name for everything else.
Also, this is an API change to before, do we want to keep support for returning -1 ? Should be easy to support.
That said, we do need a new test that is using managed files and hook_file_access() to deny/grant access I think...
Comment #23
ParisLiakos CreditAttribution: ParisLiakos commented:)
No, -1 has nothing to do with headers, its access related, we are trying to completely split them
Comment #24
Berdir@ParisLiakos:
No we are not splitting access and headers (anymore). We are splitting managed files (which handle headers automatically) and unmanaged files, for which we still have the mix of headers and access. We can't use file access for those unless we upcast them to file entities on the fly, which doesn't make sense to me.
Comment #25
ParisLiakos CreditAttribution: ParisLiakos commentedah, i see..i clearly didnt pay much attention :)
in that case, i can certainly see usecases on that
Comment #28
tien.xuan.vo CreditAttribution: tien.xuan.vo commentedRe-roll the patch
Comment #30
slashrsm CreditAttribution: slashrsm commentedReroll.
Comment #31
jibranThank you for the reroll. Code changes are fine and tests are green.
But I think we need an file.api.php change for the hook
hook_unmanaged_file_download_headers
we added here.We should add some docs that this method can return an empty array.
Comment #32
slashrsm CreditAttribution: slashrsm commentedThanks. #31 addressed.
Comment #33
slashrsm CreditAttribution: slashrsm commentedThanks. #31 addressed.
Comment #34
jibranThanks for the fix. I think we need a change notice as well but this is ready.
Comment #35
slashrsm CreditAttribution: slashrsm commentedImproved hook documentation a bit. Change record draft created.
Comment #36
jibranNice improvements and thanks for creating the change notice.
Comment #37
alexpottNot used
I'm not sure I can see exactly what bug is being fixed here. Access control still seems to be being controlled by whether or not we return headers
This looks like
$file->access('download')
returns FALSE then it is possible for aunmanaged_file_download_headers
implementation to override it. Does that mkae sense?Comment #38
BerdirThe fallback is there for things that are not managed files.. we have a few uses of that, config export is AFAIK one of them.
Maybe we can refactor it so that when we can match it to a managed file then we respect only the access controller and return FALSE if download access is denied?
That said, I think the only bug here is that we make life hard for file_entity that is trying to have more complex access logic than core is providing for files. So agreed on needing an issue summary update and possibly we need to re-classify this to task and/or not major?
Comment #39
alexpott@Berdir what i was trying to say is that if
$file->access('download')
returns FALSE then we shouldn't be calling the hook.Comment #40
Dave ReidComment #42
Wim Leers#2310307: File needs CRUD permissions to make REST work on entity/file/{id} landed, that should make things easier here.
Comment #45
marthinal CreditAttribution: marthinal at Bluespark commentedRerolled. As suggested by @alexpott if $file->access('download') returns FALSE then we don't need to call *unmanaged_file_download_headers*.
Comment #46
marthinal CreditAttribution: marthinal at Bluespark commentedComment #58
catchAs suggested in #2148353-38: File access (hook_file_download) does not use an EntityAccessController, moving this to a task.
Comment #59
quietone CreditAttribution: quietone at PreviousNext commentedThis was a daily bugsmash triage issue, adding tag.
I also made a reroll.
Comment #60
immaculatexavier CreditAttribution: immaculatexavier as a volunteer and at Srijan | A Material+ Company for Drupal India Association commentedFixed custom commands against #59