Currently, any user can download a "private" file if they know the URL. If an authenticated user knows the /system/files/private_folder/file.foo URL and gives it to someone else, that second party can access the file.

The attached patch creates a user permission that is required in order to access any file in /system/files/private_folder/file.foo. When this patch is applied, I believe this module will support a truly private file system.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Todd Nienkerk’s picture

On second thought, we should swap the conditionals on this line:

if (node_access('view', $node) && user_access('download private files')) {

To:

if (user_access('download private files') && node_access('view', $node)) {

This will cause the conditional to fail in the most common case first.

Jody Lynn’s picture

Status: Reviewed & tested by the community » Needs review

I'm not sure I understand this issue, as I believe private files does protect files successfully. Having an additional permission seems like a feature request, and I don't think a patch without a review can qualify as 'reviewed and tested by the community'

Todd Nienkerk’s picture

Jody: Prior to creating this patch, I was able to download private files when I knew the URL. If someone with access to the URL for a private file were to distribute the URL to someone else, that other person could access that file without a problem. By adding a permission control, a user must both (1) know the URL and (2) have the permissions to access that URL in order to retrieve the file. I don't see the value in making a file "private" if it can be downloaded by anyone with the URL.

After digging into the issue queue a bit, it appears this is very similar to #251033: Permissions By Role, though the patch offered here is simpler and less feature-rich.

Morn’s picture

I can confirm
"I was able to download private files when I knew the URL".
I was Testing my Site with IE6 using the Private File URL: first I got as expected "access deny", but a few seconds later the download window from IE6
poped up allowing me to download the file. (I didn't test the patch)

Morn’s picture

The Patch with Modification #1 works for me (Drupal 6.13 , PHP 5.2.8)

tizzo’s picture

Category: bug » feature

I cannot reproduce this problem. So long as I'm not logged in as user 1 and the user I am using does not have access to any node that the file in question is attached to, then that user cannot access the file. If the user has access to view that node (or any other node the protected file is attached to) the file is accessible.

This patch adds the ability to give a set of users access to nodes but not the files attached and another set that has access to both. Differentiating between accessing nodes and accessing protected files is not what this module (currently) does.

I agree with Jody Lynn, I think this is a feature request. This module is designed to prevent users from accessing files on nodes that they do not have access to. If it's correctly configured, I believe it does this properly.

Morn’s picture

Detailled Info!
My test environment was:
-in computer A an admin user with access to the file was logged in (using Firefox ).
- in computer B an Anonymous user tried to download the file using the URL to the file (using IE 6)
Result:
on computer B first appeared a acces denied message, but seconds later the donwload window from IE 6 poped up
allowing to download this file. So under this test environment
"Anyone can download a private file if they know the URL" is true for me.
Is this the way this module was designed to work or is it a bug?

Note: The download is not possible after applying the Patch.

m.e.’s picture

So, I'm confused by all the back and forth. Does this module protect files from being viewed and downloaded by an anonymous user who happens to know the URL? I have a site with NO content available to anonymous users. My testing shows that a login is necessary to see nodes, blocks, etc. that I have protected (i.e., everything) ... but if I log out, I am still able to open an image or other document if I paste its file path in the browser. I want to deny access to these files too, not just the content they accompany. Is this how? Do I need the patch as well as the module?

tizzo’s picture

m.e.: This file is really designed to provide mixed private and public files. If all of your files are really private you might just want to use the core private files setting at admin/settings/file-system.

Morn:
If you go to admin/reports/status are there any warnings from Private Upload module? You may not actually have your private files directory protected for some reason. In that case I can see how you might get this result. Morn: if you turn off the "view uploaded files" permission for the user that shouldn't have access can they still download the file with that link?

From my testing (and an admittedly brief look at the code), I'm pretty sure this module works and protects your files but does NOT provide a permission specifically for "download private files). What this means is that permission is determined by 2 things:
1. Access to the node (or nodes) that the file is attached to. If the file is attached to one or more nodes the user has access to they can download the file.
2. The user has the "view uploaded files" permission (provided by upload module)

This module relies on node_access for the rest. Maybe there's another problem but if so, boy I can't seem to reproduce it.

If this is a problem we really need to figure out what conditions allow for it. Without adding an extra permission this should work. (Though more finely grained permissions might also be a nice feature).

m.e.’s picture

m.e.: This file is really designed to provide mixed private and public files. If all of your files are really private you might just want to use the core private files setting at admin/settings/file-system.

This is too strict for my usage, however. I'm not clear if the patch addresses it. Let me explain my situation, and maybe you can tell me.

The site in question is a collaboration site for a group of engineers. They need to be able to see, download, and share drawings. Furthermore, *only* they should be able to see, download and share the drawings. If an email containing a URL happens to go astray, we don't want some uninvolved individual to be able to open these files, which are extremely confidential at this stage.

The images are displayed using Brilliant Gallery, which requires them to be stored as follows: /files/galleries/something. In our case the "something" is a series of directories called gallery1 and so on -- each one referenced in a separate node. So: the images are not, themselves, attached to nodes, which would lump them all in /files and make it impossible to group them for Brilliant Gallery.

We need a way of protecting these files from anonymous users that does not assume they are inside /files, or that they are attachments. Any thoughts?

starbow’s picture

Priority: Critical » Normal

Basically tizzo nails it in response #9 (thanks!). Everyone else might want to review the README file that describes how this module works. It tries it's best to make your private files directory actually private, by inserting a .htaccess file, but this only works on properly configured Apache systems. If you are using a different web server, or have apache configured to not obey .htaccess files, then you will need to figure out how to make your directory private on your own.

m.e.’s picture

Would it be hard to duplicate those .htaccess files in other directories to limit access to authorized users?

Morn’s picture

@Tizzo
I noticed that after a while everything works ok. I think there is kind of "Lag" (at my shared host) before a directory protected with .htacces is really protected. This would explain the access denied message parallel to the download popup.
So the correct method for me, is to wait a little before uploading critical files to this "private" directory.

Todd Nienkerk’s picture

@starbow (re; #11): The patch I included only alters one line of code -- the rest is comment text and whitespace stuff -- and does not define a new permission. Rather, it uses a permission that already exists in the module.

Even if this is an edge case, the patch I provided seems like a quick, lightweight win. This behavior was confirmed by another user.

tizzo’s picture

As far as we can tell, the behavior does not happen if the site is properly configured. This relies on Apache's .htaccess settings being respected. It also relies on you to make sure that the users in question do not have access to any nodes that have that file attached to them. If they can download files and have access to the node (i.e. it is not prevented by some node access solution like the content_access module or anything else using the acl module) they will be able to download the file.

Also, the patch does define a new permission here:

+/**
+ * hook_perm().
+ */
+function private_upload_perm() {
+  return array('download private files');
+}

The site then checks that permission in the one line here:

-      if (node_access('view', $node)) {
+      if (node_access('view', $node) && user_access('download private files')) {

Again, the functionality that this patch adds is a permission that allows you to block users access to some of the files on nodes that they otherwise have access to. This is a feature request not a bug so the question is do we want to add that feature?

Also, it means that most sites upgrading this module will need to go and turn this on or else installing the update will CHANGE EXISTING FUNCTIONALITY and cause their files to disappear/become inaccessible until they add that permission for every role with the "view uploaded files" permission. To my knowledge there is no easy way to programmatically make this kind of a permissions update.

**edit - corrected a typo**

starbow’s picture

Once again, I am just responding to agree with everything tizzo just said.

Todd Nienkerk’s picture

@tizzo: Apologies for the oversight regarding the patch. I must have confused this with another patch I've submitted elsewhere. You're obviously right to point out that it defines a new permission.

Regarding the update, it seems relatively easy to loop through all roles, check if that role has "view uploaded files" enabled, and enable the new permission accordingly. This update would mitigate the problem of changing functionality.

I wouldn't describe myself as a developer -- and definitely not a sysadmin -- but I do have more technical know-how than the vast majority of Drupal users. If I can't configure my server properly after an hour or two of research, I doubt most users can. (Also, what about shared hosts? Do most low-end hosts allow access to change these settings? I don't know.)

I propose that instead of disqualifying users who don't know how (or can't) configure their server, an additional layer of security be added to the Drupal layer by adding a simple permission.

tizzo’s picture

@Todd Nienkerk: Most shared hosts do respect .htaccess files (and if they don't Drupal will have bigger problems to worry about). If their server is not properly configured adding this check won't prevent them from downloading the files either.

Do your users that can access the file have access to view the node? Again, the only time this module will step in and protect those files is if they do not have access to any node with that file attached.

This module essentially protects files using the node access system. It does that perfectly. If you're not using the node access system to restrict access to those nodes then your files will be public. The question is whether we want to add another way to restrict access (by role), not whether we want this to work for more users.

You're right though, the fact that we are having this discussion probably means the documentation could be clearer.

Also adding the permission is actually going to be a bit of a pain, there's no API for that. In all Drupal versions prior to 7 the permissions are stored as a comma separated list in the permission table (which is kind of crazy). This certainly isn't functionality that we need (and in fact is another box we'll have to remember to check each time we setup a site). If this is a feature other people want then please, write an update patch as we'll definitely need one to keep from breaking sites. I'll offer to help test it.

Todd Nienkerk’s picture

Does this module rely on cron or other periodic processes to assign access permissions to certain files? That might explain why Morn and I were able to download private files -- if perhaps only for a few minutes after attaching them.

starbow’s picture

No. It relies on an .htaccess file. But it is possible that your website provider has their version of apache configured to only look for new .htaccess files at set intervals.

vuzzbox’s picture

Again, the functionality that this patch adds is a permission that allows you to block users access to some of the files on nodes that they otherwise have access to. This is a feature request not a bug so the question is do we want to add that feature?

I would vote in favor of adding this feature. Configuration or misconfiguration of htaccess aside, there are good reasons for applying this patch. Here's my scenario and here's how it would help me:

I am requiring registration for access to some, but not all, uploaded files on my site. When someone visits my site, he can view a library of "registered user only" resources (pdfs on different topics). Each resource is presented as node with the file attached through the core file attachment. If the user is not logged in, when she views a "resource" node, she is presented with information about the file and a login form that will allow her to gain access to that and all other private resources in the library. If she is logged in, she is presented with a download link. I do this through a combination of Contemplate and Webforms. It gives me the ability to let people roam freely through the library to learn about what we've got to offer, but limit access to the goods (downloadable files) to only registered users.

So, I have one node that needs to allow anonymous access to "advertise" the resource and, conditionally, needs to allow access to a file attached to the resource to authenticated users only.

So making access to the file contingent on access to the node is limiting in my situation. I'm applying the patch.

SomebodySysop’s picture

Thanks for the patch. I, too, have used it with great success. It should be the default functionality for this module.

I have added some additional features to the patch, if anyone is interested:

1. Before, users who did not have access to private files could still see the file links in the nodes. This patch makes the files invisible to users who do not have access.

2. Created a column so that admins and users who have access can see which files are public and which files are private.

Combined with OGUR, I can now assign group specific access to private files so that users can only see them if they have the role in the specific group.

Again, thanks.

xecstasyx’s picture

it works, i hope someone finds a solution to views links also , thanks!

pjsz’s picture

@#22 -- Thank you for the patch. This module is great. I believe the "download private files" is a much needed addition. With it , this module serves my needs of only letting authenticated users access files attached to nodes while still leaving other files open to all users with view uploaded files permission which is everyone on my site.

I also need some other features which i can program and submit a patch . I need to hook into the access routine to do some custom role based, file based permission. -- Example of what i do currently in hook_file_download --

If ($node->restricted_access and !user_in_role('confirmed_faculty')) 
{ 
   // Only confirmed faculty can access file on restricted nodes
   return -1;
}


So I have a need for role based and custom php access routine. I wonder if on the settings of this module there could be a php area for access to private files? Additionally and role based access on a per file level would be nice and solve my problem as well. Is there a module for that ? Instead of just a single checkbox for make private on the upload attachments form , have a multiselect with roles -- not private(anyone), anonymous, authenticated, confirmed faculty, admin. Anonymous would be the equivalent of anyone i think and not put any rows in the database and be the default. Any thoughts , suggestions?

I finally read a little slower and saw above discussion and link to the role selection patch. Still can't get the role based access working.
But Patch in #22 does not have role selection in it the attachments form. What is OGUR? I followed the link to the other thread on role based permissions and it does not work for me. I get the selection but everyone can access the files. AFIK, we still need a working patch for d6 for role based access and permission bassed on access private files permission. Is that right?

thanks

pjsz’s picture

Question about this module's use of hook_file_download. The hook_file_download docs it says that that hook is only for private file downloads. I'm confused.

thanks

pjsz’s picture

I see. It changes the url to the one it would be were the private files turned on. Cool trick. Is that feature documented anywhere? IE -- if you make you path go through /system/files you get your hooks called? Cool.

karchie1’s picture

thought as long as you set the private folder to be above the drupal root you couldn't directly link to the file outside of drupal? are you having this issue just because you're setting your folder to be inside the drupal root somewhere?

kscheirer’s picture

Title: Anyone can download a "private" file if they know the URL » Add permission to separate files marked private from the generic 'view uploaded files'

@tizzo good summary, I think you fully understand the issue.

This feature gets my vote, as it would neatly solve my problem.

My use case is similar to some others posted here: The node is always viewable (not using any acl). Some nodes have files that anyone can download (requires 'view uploaded files'), but some files are only downloadable by authenticated users.

This patch gives me that second permission ('download private files') to restrict the files marked 'private' but still allow anonymous users to download non-private files.

I'll post a review with any problems after running this patch for a bit. Changed title to better reflect the discussion.

jrsinclair’s picture

I have a very similar use case to @kscheirer and would like to vote for this feature too.

From the discussion above, it appears that private_upload module works exactly as it's supposed to, but I would like to make a distinction between permissions for private updoads and public uploads. That is, I would like to allow anonymous users to view uploaded files that are public but prevent them from viewing uploaded files that are private. I had hoped I could do this with a combination of the node_access module and private_upload, but on testing it appears that this will not work. It seems that the node_access module's hook_access() does not get invoked when private_upload calls the node_access() function.

Adding a 'download private files' or 'view private files' permission would allow me to grant access to private files to some roles while denying it to anonymous users, but still allow anonymous users to see lists of public files attached to nodes.

If anyone knows another acl module that does get invoked or can tell me a way to make private_upload invoke node_access module's hook_access(), I would love to hear about it.

Renzy’s picture

I can also confirm that the orginal patch for this module was successful. The nodes can be viewed by anonymous users but the attached files to those nodes can be private. The second patch supplied in this thread produced an error for me in the terminal when I tried it.
Renaee.