Is there any implementation of file download access control yet in the OG 7.x-1.x-dev ?
I couldn't find any, and my tests with a private file system and file fields on private group posts suggest the same.
If not, I guess it is a case of implementing hook_file_download() and checking the user access to the fields and/or nodes in question.
Have I missed something or is this in the pipeline?

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

amitaibu’s picture

Status: Active » Postponed

> Is there any implementation of file download access control yet in the OG 7.x-1.x-dev

No, and I currently don't plan one -- although patches are welcome, if they show a good use case.

smls’s picture

Does this mean it's not possible to allow groups members to upload private files which no-one outside the group should be able to access?

If so, ecofinn, could you consider sharing your hook_file_download() implementation if you come up with a working one?

(Btw, is this also not possible in OG 6.x?)

Finn Lewis’s picture

Here's a quick first stab at the file access function. I popped this in a og_file_access.module and it provides some basic access restriction based on whether a user has view access to the node.

/**
 * Implements hook_file_download().
 */

function og_file_access_file_download($uri) {

  // retrieve list of all fields
  // @todo - retrieve list of only file fields
  $fields = field_info_fields();

  // loop through fields
  foreach ($fields as $field) {
    // currently only interested in fields of type 'file'
    if ($field['type'] == 'file'){
      // get the field name
      $field_name = $field['field_name'];
      // query the file_managed table for a list of nodes (entities?) this file is attached to
      $result = db_query("
	       SELECT f.*, doc.*
	       FROM {file_managed} f
	       INNER JOIN {field_data_" . $field_name . "} doc ON f.fid = doc." . $field_name . "_fid
	       WHERE uri = :uri",
	       array('uri' => $uri));

      // loop through the resulting entities
      foreach ($result as $entity) {
                
        // check if the current user has access to view the node
        if (!node_access('view', node_load($entity->entity_id))) {
          // deny access
          return -1;
        }
        elseif (!field_access('view', $field, 'node')) {
          // deny access
          return -1;
        } 
        // @todo add an elseif for og_field_access_check_access()
      }
    }
  }
}

So for a file attached to a node that was only visible to group members, non group members are denied access to the file (assuming it is uploaded to the private file system, of course).

I'd like to improve on this by making use of the og_field_access_check_access function, but not quite got to grips with what to pass it yet - still getting my head around these shiny new 'entities'.

I guess this function should also check user access to other entities that the file might be attached to, not just nodes.

amitaibu’s picture

@ecofinn ,

You can keep reporting here, but this module should live in contrib.

Also note that files are entities so you can use EntityFieldQuery() for the query.

Finn Lewis’s picture

@Amitaibu,
thanks for your comments, I'll get my head around entities and look into EntityFieldQuery.
Can you give any pointers on using og_field_access_check_access to check if a user has access to a field?

amitaibu’s picture

> Can you give any pointers on using og_field_access_check_access to check if a user has access to a field?

You don't have to use og_field_access_check_access, you can set the field #access property in your own function if you want.

geerlingguy’s picture

Subscribe.

mthart’s picture

subscribe

seattlehimay’s picture

Subscribe.

Matt B’s picture

Subscribe

Matt B’s picture

FileSize
873 bytes

I've attached my og_file_access module based on ecofinn's post (#3). My tests so far show this works fine.

wanghl165’s picture

Subscribe

Matt B’s picture

FileSize
858 bytes

Slight modification - if you have more than one file field, the original code stopped after interrogating the access rights on the first file field, and if it found there were no view rights it would return. The modification below and attached loops through all the file fields.

<?php
/**
* Implements hook_file_download().
*/

function og_file_access_file_download($uri) {
  // retrieve list of all fields
  $fields = field_info_fields();
  $denied= TRUE;

  // loop through fields
  foreach ($fields as $field) {
    // currently only interested in fields of type 'file'
    if ($field['type'] == 'file'){
      // get the field name
      $field_name = $field['field_name'];
      // query the file_managed table for a list of nodes (entities?) this file is attached to
      $result = db_query("
           SELECT f.*, doc.*
           FROM {file_managed} f
           INNER JOIN {field_data_" . $field_name . "} doc ON f.fid = doc." . $field_name . "_fid
           WHERE uri = :uri",
           array('uri' => $uri));

      // loop through the resulting entities
      foreach ($result as $entity) {
        // check if the current user has access to view the node
        if (node_access('view', node_load($entity->entity_id)) && field_access('view', $field, 'node')) {
          // allow access
          $denied= FALSE;
        }
      }
    }
  }
  if($denied) return -1;
}
?>

Probably needs rewriting as suggested to use EntityFieldQuery() but I've still got to get my head around that!

Matt B’s picture

FileSize
1.04 KB

Found a problem with this code in that it blocked any files that were not attached to a node and any files attached to a node that was not a group content type. I've made some more tweaks - see attached.

fago’s picture

mthart’s picture

subscribe

Matt B’s picture

#15 - maybe it should, but it does not appear to do so as without putting this module in place anyone who knows the url to the file can access it without even being logged in.

mortendk’s picture

subscribe

zarkinfrood’s picture

subscribe

bochen87’s picture

Category: support » feature
Status: Postponed » Reviewed & tested by the community

subscribe! works great, should be integrated into og!

can you change the line:
if ($field['type'] == 'file'){

into

if (($field['type'] == 'file') || ($field['type'] == 'media')){

this way media files will also be taken into account

amitaibu’s picture

Status: Reviewed & tested by the community » Needs work

@bochen87,
There's no patch attached, so it can't be ready to be committed.

bochen87’s picture

its a single module which Matt B created in #14, so maybe you can add it as a plugin or something?

Matt B’s picture

FileSize
1.16 KB

bochen87 - good call, updated tarball attached including your change.

Amitaibu, should I create a contrib module? I'd prefer to see this level of security implemented into OG itself because without this one cannot create truly private groups.

bochen87’s picture

Maybe ou could also modify the return:

if($og_content_attached && $denied) {
return -1;
}
elseif ($og_content_attached && !$denied) {
$file = file_uri_to_object($uri, TRUE);
return file_get_content_headers($file);
}

Notice that file_uri_to_object comes from Media module. Maybe you could use some drupal internal method to get the file?

othermachines’s picture

subscribe

bluestarstudios’s picture

Hmmm. Somehow this isn't working for me. Using latest dev of OG and installed this extra module and still can't get it to work. Can somebody please help?

I have a file field (private storage) attached to a node which is a Group Content Type. The admin can see the node and access all the files, however other group members can only view the node. Clicking on the files gets them to "Access Denied" and Notice: Undefined index: field_name in og_field_access_field_access() (line 60 of /Applications/MAMP/htdocs/public_html/drupal-7.8/sites/all/modules/og/og_field_access/og_field_access.module).
Non-members however can't see the node (correct behavior), and get the same above-mentioned error if they try to access the file directly.

I need group members to be able to download the files. Your help on solving this issue would be GREATLY apprecated. :) Thanks.

bluestarstudios’s picture

Can anybody please help with getting this working? it doesn't work for me under Drupal 7.8. See my post above. Thanks in advance.

sveloz’s picture

I have not studied relevant hooks. I just have a notion of the difference between the public and private file storage, and that other modules also do have access control to files in the private file storage, here I checked for modules in the core: http://drupal.org/project/issues/drupal?text=file+access+control&status=.... Also I have not tested the issue, so I don't speak from experience with it.

The og_file_access_file_download() first query all the fields through $fields = field_info_fields(), and then goes through everyone if the $field['type'] == 'file'. @ecofinn wrote in the issue summary that he's seeking access controll for files to make true private groups. Is this function ment for file access control for groups, where the file is attached to the group (meaning there are never file attachments to other content types)?

The thing I wonder about, is that the access control in #13, uses node_access() and field_access(). It sounds to me that this code can be used for file access control for nodes as such (identified by node-ID), rather than exclusively for group content types as such (identified by node-ID + the group audience field), where the files are attached to a node (which can be a group, or be a normal content type f ex an article). Therefore maybe this function could've gotten another name and got under one of the core modules, for a more general use for file access to the private file storage, when files are attached to nodes? The node module is also in the core.

Another angle may be to limit the file attachment to groups, where groups in the code is identified by the node-ID. @ecofinn wrote in the issue summary that he's seeking access controll to make true private groups, but I see a more broad use scenario for this when using node_access(). This way it is possible to attach files to any node type, either it's a group or an article f ex, and make the visibility shine in relation to the node. This way you can make a file field in any content type, and have the file via that field private, no matter which content type the node is. Therefore I think this could be a feature for some of the modules in core. I don't have much experience about the core to figure how to do this, but I'm sharing the thoughts.

amitaibu’s picture

If we are talking about files in nodes, I would think that Drupal core should take care of this. If user has no access to the node, they should not be able to access a file in it. OG isn't responsible for this.

Matt B’s picture

But with OG installed private files are accessible to users that do not have access to the node. So either Drupal is broken or OG is allowing access rules to be circumvented. Hence the reason for this module (or something similar....)

Is this because OG is not implementing hook_file_download? (Or I assume it doesn't as I've not double checked...)

I think this functionality should be in place when installing OG (regardless of whether it's provided by OG or Drupal core).

Amitaibu, thanks for all the great work you are doing on OG!

sveloz’s picture

My experience with this issue is that sometimes, when the file access controll is determined by weither a user has access to a particular node, the access control is not hardly related to the action of a user viewing that particular node. Sometimes, which is the case for OG, there should be some kind of hook for access control for the file in relation to a node, when a user are viewing something else than that particular node who determines the access control. Either there could've been access control for a file in relation to a node, which is the track you are working on, or there could've been access control just for the file itself, which could've been a feature request for the appropriate module in core. If there were a general use hook, this may be reused with files viewed/downloaded through taxonomys and other entities too.

If this is solved within the core, with a hook for contributed modules to use, I brainstorm a littlebit that there are oportunities for contributed modules. Technically it could f ex made an image available on any node, where there are a seperate access control hook for the (image) file in the private file storage, either the access control is related to a node or is just for the file itself. The user do see the node, but do not nessesary see the image. My point is that this opens oportunities for other modules than the OG too. Maybe this is a limitation that is videly aksepted and ok, not challenged by feature requests. I think downloadable files outht to be downloable via something elses URL, for the file not to be accessable with a direct URL. But this issue is about access control when a file should have its own access control hook (for modules to use), not hardly related to viewing the node in which the file was uploaded through.

As I understand the problem, files are accessible to anybody (including anonymous users, se #17 and #30) because there are no access control in place, which is because there are no hook for that for modules to use. It is true that nobody can access a file through a node he hasn't access to, that is rather logic, but this is about accessing a file at other nodes than the node in which it was uploaded through. (Or virtually through other entities.) Here access control for the node as such, and no access control for the file as such (in relation to the node or by itself), is not enough. As long as it is videly aksepted that no file in the private file storage should ever be accessed by other means than through the node in which it was uploaded through, this is no problem. But the "true private OG" challanges this. Maybe it is a matter of that organic groups is a content type with the uniquely field "audience", and is not an entity of its own, which is the common practice for other subjects in drupal which does need it's own fields for some sorts of cross referencing. I'm now thinking about the "audience" field as a sort of cross referencing.

I don't know about if there are several use scenarios (I don't take the time to digg into it), but either way I agree with Matt B that the hook should be somewhere for the case of this module, either it's in this module or in core.

David4514’s picture

FileSize
2.47 KB

The module in #23 came close to what I needed. However, it interfered with another custom module which also was controlling access to other private files (unmanaged).

I needed some way to keep these from tripping over each other.

I added an administration interface which allows you to specify the directories that may be used for OG File Access. Nothing fancy here. An improvement might allow wildcard matching or subdirectory support. This simple implementation is enough for me.

In the hook og_file_access_file_download I first check to see if the directory requested matches one of the directories specified in the administrative interface. If it does not match, then I return NULL to allow other hook_file_download implementations in other modules to have a shot at controlling their directories.

If it does match, I first check to see if we are dealing with an anonymous user. If we are, I deny access.

After that, I pretty much follow the original logic with the exception that if we accept the download, I return the Content-Type and Content-Length that are needed to access the file.

Matt B’s picture

I moved to Taxonomy Access Control - it seems to suit my needs better than OG, however I noticed the same problem - nodes where private, but the attached files available to anyone with the direct URL. On close investigation I found an issue with an old version of the Media module which I also had installed. Media essentially overrode the content visibility permissions. Might be worth checking if you have Media installed if you are experiencing this issue yourself. Unfortunately Media would not cleanly uninstall, and I've had to rebuild the site from scratch...

Morten Najbjerg’s picture

subscribe

Morten Najbjerg’s picture

I'm currently pulling all my file lists out through views.
The access control seems to be having some problems allright - but in my case it would be an ok temporary solution to show the files to the user based on the groups he or she is a part of.
I thought this would be a matter of creating the right contextual filter. A filter doing a "Filter content only posted in groups the currently logged in user is a member of".
Is this possible?

Under normal circumstances such a filter would not be relevant as the access control will automatically leave out the results that the user is not allowed to see. But in this case the files are shown anyway

Jackinloadup’s picture

This will be relevant to this thread as soon as it lands in file_entity #1227706: Add a file entity access API

Here are corresponding patches for other relevant modules:
media #1677054: Use file_entity_access() instead of media_access()
media_browser_plus #1721524: Use file_access() instead of media_access()

It would be awesome to see file_access() supported in og as well,

ehsankhfr’s picture

Issue summary: View changes

#32 worked for me! Thanks!

davidpugh’s picture

#32 seems to have fixed the same issue for me as well. I have a private file system set up with drupal that is not in the public directory for apache. For content that has attachments and the user trying to access that attachment doesn't have permissions to view the node then they get denied (for content not related to organic groups). For organic groups this didn't seem to work though. Installing module from comment #32 fixed this problem and now if the user trying to access an attachment from a piece of group content doesn't have permissions to view that content the attachment is attached to they get an "access denied" on viewing that attachment.
Thanks David4541!!!

kaicyee’s picture

subscribed.

davidpugh’s picture

Hey people!
I commented (comment #38) that the module given in comment #32 worked for me, but just recently I found that the module was not actually working. Not sure if it was ever working for me, but found that it was not.

Looking at the code in the module the module expects your content type to have a field:

Group content visibility
machine name = group_content_access

Which is assigned in og field settings page: admin/config/group/fields

My content type did not. It had a field:
Groups audience
machine name = og_group_ref

But the module expects you to have a Group Content Visibility field.

After adding the field the module was STILL not working, and I used Devel log to find out that the module was looking for the node to have:

isset($loadnode->{OG_CONTENT_ACCESS_FIELD}[LANGUAGE_NONE][0]['value'])) {...}

but looking at my $loadnode properties in devel log my node had:

group_content_access (Array, 0 elements);

so it did not have the extra properties that the above code was looking for:

[LANGUAGE_NONE][0]['value']

My content type is translatable but with field translations. I am guessing that the:
[LANGUAGE_NONE][0]['value']

is assigned if it is translatable but regular translation (not field translation).

So if you try the above module from comment #32 and it does not work for you you might need to edit
the isset field I described above, or change your content type so that it has the
[LANGUAGE_NONE][0]['value']
property in the array:

group_content_access

which is a property of the node.

********UPDATE************
I just checked and whether
$loadnode->{OG_CONTENT_ACCESS_FIELD}
has the :
[LANGUAGE_NONE][0]['value']
property
DOES depend on whether you have it be translatable or translatable with field translations.
If you have your content type set to "field translations" then when you add

Group content visibility

field to the content type it won't contain the
[LANGUAGE_NONE][0]['value']
property and the module won't work.

You can update the og_file_access.module so that the call only checks for

if ($entity->entity_type == "node" && isset($loadnode->{OG_CONTENT_ACCESS_FIELD})) { ..}

and leaves off the
[LANGUAGE_NONE][0]['value']
check.

geek-merlin’s picture

Isn't it solved by this?
https://www.drupal.org/project/ogfile

davidpugh’s picture

axel.rutz -

The module given from comment #32 allows access if the content type is an organic groups content type AND the person trying to access the file can access the node the file belongs to.
Looking at the module you linked us I can't really tell what it does....(also I couldn't tell from looking at the code in the module).

It's talking about a file bundle.....I don't know what that is.
Are you using the ogfile module?
If so can you very explicitly define how it works?

I think most people will want to have a file field on a content type that is an organic groups content type and will want the user to be able to resolve the url of that file ONLY if the user can access the node the file belongs to.

Thanks!

geek-merlin’s picture

> and will want the user to be able to resolve the url of that file ONLY if the user can access the node the file belongs to.

Ah, THIS kind of access control. No, that module announces something else, permissions by file entity bundle.

joseph.olstad’s picture

please see the related issues:

#2932229: Unable to create or edit a Document Page in Section unless administrator

#2067671-35: Ensure file query alteration is performed when using EntityFieldQuery

TO make a long story short, OpenAtrium appears to be able to do this using organic groups, which up until August 2017 was successfully using file_entity 7.x-2.0-beta3 however a regression however came in when in August OpenAtrium upgraded their panopoly distribution which had also updated to file_entity 7.x-2.12 , I stumbled accross the issue when I installed OpenAtrium myself and managed to find the commit that caused it.

I've committed and released a version of file_entity (7.x-2.15) that has a workaround that allows OpenAtrium organic groups permissions to work correctly again. However OpenAtrium decided to use a different patch which reverted a large amount of code , I'm still reviewing and haven't decided whether or not to follow what OpenAtrium did in their latest release (using the patch 2067671-35 a significant revert to file_entity.module)

just thought I'd share this info with this issue, seems possibly related as OpenAtrium is using organic groups and has access control for private files , seems to work well as far as I can tell.

there may be some special OpenAtrium custom code however doing some extra magic sauce though.