I created this security module for Drupal - my first stab at Drupal development.
"Node File Access", as it is called, uses a host of generic approaches to identify files uploaded/created and used by modules like IMCE, Galarix and Upload, and associate them with the respective nodes that use them. The access to those files is then monitored by Node File Access, and access is granted to the files only if the user requesting it is able to access the node with which the file is associated. It maintains those associations dynamically (that is, it keeps updating associations as the use of the files move from one node to another or new files are added or files are removed from a node; resolves conflict of association when multiple nodes use the same file; protects associated files when a node is deleted) and gives access to files based on whether an user have access to the node to which the file associated to. It is also possible to manually search for and alter associations, or explicitly mention not to associate certain files with any node.
The module was under review by Drupal developers community. However due to too much triviality in the review process, and my lack of time to attend to those, I have voluntarily took off from the review. However, you can download the module here for your use under GNU-GPL.
Description and documentation:
Node File Access
Version 1.0
Installation and Use:
=====================
The installation procedure is standard:
i. Copy the node_file_access folder into the 'modules' folder.
ii. Activate the module from admin/build/modules
iii. Set permissions for users from admin/user/permissions
- For configuring settings of Node File Access and to rebuild associations use admin/settings/nodefileaccess
- For managing the Exception and Protected files use admin/content/nodefileaccess
- The files associated with each node can be monitored from "Files associated with this node" block of each node's edit page
Description:
============
Node File Access uses a host of generic approaches to identify files uploaded/created and used by modules like IMCE, Galarix and Upload, and associate them with the respective nodes that use them. The access to those files is then monitored by Node File Access, and access is granted to the files only if the user requesting it is able to access the node with which the file is associated. It maintains those associations dynamically (that is, it keeps updating associations as the use of the files move from one node to another or new files are added or files are removed from a node; resolves conflict of association when multiple nodes use the same file; protects associated files when a node is deleted) and gives access to files based on whether an user have access to the node to which the file associated to. It is also possible to manually search for and alter associations, or explicitly mention not to associate certain files with any node.
Motivation:
===========
Presently a very few modules (like the Upload module) reliably monitors the access to files based on the permission of the node to which the file was uploaded. However modules like IMCE (http://drupal.org/project/imce) or Galarix does not monitor the access to files uploaded through them. For example, in creating a node, say "node/n", an authenticated user makes use of the IMCE or Galarix modules to upload a picture IMAGE.jpg. For the authenticated user this image is obviously available through, say http://mysite.com/drupal/sites/default/files/IMAGE.jpg (or http://mysite.com/drupal/?q=system/files/IMAGE.jpg). Now say, the authenticated user sets protection for the node using modules like Protected Node (http://drupal.org/project/protected_node) or Nodeaccess (http://drupal.org/project/nodeaccess) such that a visitor will not be able to access the node "node/n" or will be able to access only using a password. However, in spite of protecting the node, a visitor will still be able to access the image file using the direct URL http://mysite.com/drupal/sites/default/files/IMAGE.jpg (or http://mysite.com/drupal/?q=system/files/IMAGE.jpg).
Explanation:
------------
This happens because IMCE or Galarix (and many similar modules) do not implement a hook_file_download. Many of them (like IMCE) don't even keep record of which node was used to upload a particular file (often it doesn't even make sense to do that since a file may be used by multiple nodes). Thus protections applied to the nodes does not apply to the files themselves.
The solution:
=============
The Node File Access module tries to solve this issue in two stages:
1. First it uses a host of approaches (that is flexible for modification) to identify which files are associated to which nodes. This includes looking inside the HTML content of a node to find references to files as well as looking into different databases of other modules. How the look-ups are performed can be monitored form the module's settings page.
A file is associated with only one node (even if it is used by multiple nodes), and the author of a node will have the ability to transfer the association to a different node manually. Typically the node that used the file first will have the association of the file and will be able to "lock" the association by default. Unlocking the association from a node will enable other nodes to claim association of a file.
Thus it populates, maintains and monitors association of files with Drupal nodes.
It maintains these associations dynamically (that is, it keeps updating associations as the use of the files move from one node to another or new files are added or files are removed from a node; resolves conflict of association when multiple nodes use the same file; protects associated files when a node is deleted) and gives access to files based on whether an user have access to the node to which the file associated to. It is also possible to manually search for and alter associations, or explicitly mention not to associate certain files with any node.
2. Next, when a request for a file is received (say http://mysite.com/drupal/sites/default/files/IMAGE.jpg or http://mysite.com/drupal/?q=system/files/IMAGE.jpg) Node File Access first redirects to the corresponding associated node ("node/n" in our example case). If the node loads completely (i.e. without receiving access denied or a password request from some arbitrary security module) and no other module prevents the file from being downloaded, only then does Node File Access sends back the requested file.
In order to monitor access to direct URL-based file requests like "http://mysite.com/drupal/sites/default/files/IMAGE.jpg", Node File Access alters the .htaccess file at the Drupal root to redirect such requests appropriately (in this case to "http://mysite.com/drupal/?q=nodefileaccess&file=sites/default/files/IMAGE.jpg"). Node File Access also implements a hook_file_download to monitor requests like "http://mysite.com/drupal/?q=system/files/IMAGE.jpg".
The Node File Access module lets an administrator control how Node File Access looks for and create association of files with nodes. It also lets creators/editors of nodes control whether to not associate a particular file with the node or whether to lock some associations with a node.
Technical details:
==================
The following workflows describe how Node File Access works:
1. A request for "http://mysite.com/drupal/sites/default/files/IMAGE.jpg" is received.
2. Apache redirects the request to "http://mysite.com/drupal/?q=nodefileaccess&file=sites/default/files/IMAGE.jpg" (the redirect rules are written and maintained by Node File Access in .htaccess file of Drupal's root).
3. The 'nodefileaccess' menu takes over and looks up the association table to find associated node "node/n".
4. A redirect is set to "http://mysite.com/drupal/?q=node/n&file=sites/default/files/IMAGE.jpg".
5. All the callbacks corresponding to "node/n" gets processed, and hence, if at any point, a security block is encountered, the process stops.
6. If the $_GET['file'] parameter is set, Node File Access takes back control at the 'alter' level of 'nodeapi'.
7. Node File Access once again checks if the requested file is associated with "node/n", and then passes on the request to Drupal's 'file_download' function.
Note that due to the step 7, it is not possible to fake an association by sending a request like "http://mysite.com/drupal/?q=node/m&file=sites/default/files/IMAGE.jpg".
If a request for "http://mysite.com/drupal/?q=system/files/IMAGE.jpg" is received instead, Node File Access's hook_file_download takes over, and redirects to "http://mysite.com/drupal/?q=nodefileaccess&file=sites/default/files/IMAGE.jpg". Then the above work flow continues from step 3.
The population and maintenance of the association table is done using a host of SQL queries and RegEx based searches that can be defined/modified in the module's settings page. Users can see and change the associations from the individual edit pages of each node.
IT Projects Drupal