Currently, anyone allowed to use the WYSIWYG + Media combo will be able to upload/attach any media enabled. For instance, they could attach youtube, flickr, video, audio, pdf, javascript, etc. in addition to images.

We need to visit this, probably by adding broad-based role permissions, and/or by fine-tuning allowed uploads/attachments in the wysiwyg profiles + filter formats. The configuration should be simple, and work hand-in-hand; for instance, if a user is not allowed to attach youtube videos by role, then the wysiwyg browser shouldn't even load up that tab. Or if a profile doesn't allow anything but pdf's, the browser should respect that, not even offering images in the running.

Media as a field would solve this particular issue in one direction, by configuring what's allowed in a specific field. However, WYSIWYG is more global, so I suspect that configuration should happen when a filter is defined. The hooks for modules to tap into should be well-defined, so that media_youtube could, for instance, simply implement or check the hook or alter for permission, turning on or off its tabs and allowed media. That particular hook shouldn't care if it's being called by the field or by WYSIWYG. (Perhaps role-based perms are inappropriate here.)

I suspect an API hook might be a way to go. The original specification allowed for this when a module was registered. That registration system has been scrapped, but we desperately need to tackle this issue again.

Comments

JacobSingh’s picture

Showing tabs in the browser should be an option passed in by the caller IMO. Showing or not showing isn't going to provide any level of access control because it can totally be faked.

WYSIWYG is protected by input filters, and I kinda feel it should stay that way. I'm not opposed to a check on submit though to make sure you didn't try to use something you aren't supposed to. Still, seems like duplication of effort.

Applying permissions to plugins is a simple enough matter though if we want to go that way. I think though that it is cleaner to have the callsite get a setting of how to launch the browser than to hard-bake permissions logic into what is just a display tool. (then you could show youtube in WYSIWYG, but not other places). We need this anyway because media as field needs to launch and pass in params.

Regarding how permissions are structured, this is dodgy. We don't want to replicate node access. That is a royal clusterf*ck and we all know it. Plus, it won't scale when you have a gallery. My feeling on it is we should investigate if entiies give us anything for free. IF not:

media type x role permissions is a good place to start, and will be fairly quick, can be cached as well.

When launching the WYSIWYG do we need to hardbake the role x type condition into the library callback? Or do we just pass in conditions for the library.

Anyway, that's not real validation:
1. WYSIWYG input filter will not render things you aren't supposed to pick
2. We need to pass what tabs should be included when the media browser launches. To accomplish this, we can simply pass in options. The downside is that this means the forms -upload, from url - get rendered anyway (Something I was trying to avoid by making it all load real-time), but at least the library gets ajax loaded.
3. The options should really be related to the input format (if that's possible), not global IMO... But if we have to do global, that works too.

In Sum: I'm open to whatever, I'm more interested in passing options to the browser than hard-baked rules and assumptions on the server side, and if we start calling a function everytime a piece of media gets loaded to check its perms, we're going to be in trouble.

Rambling,
Jacob

aaron’s picture

we first talked about this back in january at nyc, and again in october: one big issue would be that a person could fairly easily browse through all the private files in a system just by incrementing through fid. even if it's just thumbnails & filenames, that might be too insecure on some installations.

additionally, though the new conditions in media_browse_list will handle this, one might only want to list their own files (even if they are allowed to view all files on a system).

JacobSingh’s picture

Hmm... yeah, this is a PITA. It seems to me a like a global entity_access API is in order or something. node_access is such a drag to work with and so slow, it makes me worried here when you have thousands of files.

I guess it's only for people who want to turn it on, which is probably not too many.

One thing we are not respecting though, which we probably should now is if someone gives access to anonymous users, they shouldn't see private:// files I suppose.

So I guess we have 3 approaches:

1). Call a function on every entity_load() with a hook to either load or not load the media based on arbitrary access rules

2). Maintain a potentially *massive* table of ACLs like node_access does - and a system for this.

3). Make a few permissions like: view_$type and edit_$type, and just use those perms in various places where we need to get media / show stuff relating to those types.

unless we have to do one of the first 2, the 3rd one is really attractive in that media types are flexible instruments and the check will be quick, and can be done w/ SQL instead of on a per media basis.

We can always do the first 2 in addition or later as well.

This becomes a lot easier to think about when we've got a custom EntityController I think.

aaron’s picture

Status: Active » Needs work

i don't know about EntityController yet. sounds like something the project could benefit from, though (from the sound of that class name...)

i've got some stuff in place w/ media_browser, which may not be the best place for it:


  // Allow modules implementing hook_media_browser_conditions to add new
  // conditions to load the library. For instance, they may only return media
  // belonging to the user, with array('uid' => $user->uid);
  $conditions = module_invoke_all('media_browser_conditions');

  // Allow modules implementing hook_media_browser_conditions_alter to alter
  // the set of browser library conditions.
  drupal_alter('media_browser_conditions_alter', $conditions);

  // Allow modules implementing hook_media_browser_conditions to filter streams
  // when loading the library. For instance, they may only return media
  // belonging to the flickr:// stream, with array('flickr://');
  $streams = module_invoke_all('media_browser_streams');

  // Allow modules implementing hook_media_browser_streams_alter to alter
  // the set of browser stream filters.
  drupal_alter('media_browser_conditions_streams', $streams);

Might be better to put the alters in media_browser_list() -- basically, (and I've done this experimentally), it allows us to add a global condition by role permission, for example. I'll work more on this to get it working w/ the anon/private case at least (which will also be a good use case as well as a proof of concept).

aaron’s picture

in fact, maybe the hook_media_browser_conditions & streams isn't needed at all, and only the alters. that way each tab can define itself normally, then the alters can affect them globally if needed.

JacobSingh’s picture

I'm a little concerned here. I thought we discussed this and came to a decision, which was:

1). Someone is going to write a views plugin for this which will do everything we do

2). Making our code complicated or slow, or building a flexible framework around it won't help, because Views is Views and we don't want to do the same stuff

3). This code seems to be doing the same thing views does

4). We will have 3 *harcoded* filters, by type, by uid and by url LIKE "%search%".

This will support "youtube://%", it will support "%.jpg", and it will support "Only Images by me".

I don't understand hooks like this:

$streams = module_invoke_all('media_browser_streams');

  // Allow modules implementing hook_media_browser_streams_alter to alter
  // the set of browser stream filters.
  drupal_alter('media_browser_conditions_streams', $streams);

When you've already got a place for conditions, etc. Further, but specifying $streams, won't it just go on to specify extension? and then size? and then lyrics in the id3 tag, and then resolution, etc. etc.

Isn't this all better served by using an actual query builder?

See http://drupal.org/node/697106#comment-2567976

JacobSingh’s picture

Thinking more about this, any type of permissioning should be done at the EntityController level or immediately above it through some API interface. But probably in the EntityController itself.

Because if you do something like what is written above, there is a not a consistent interface on which to deny access or grant access. I think first we need to determine what we are going to do access control for. I think I stated my idea that a first pass would be type X role and "My stuff" vs. everyone elses stuff. This is Core's default behavior for nodes.

But either way, we need to have it in the load mechanism, so whenever a media entity is loaded, the check is done.

I would however, recommend that we start with access control which can be incorporated into the SQL to select the fids. this would be in MediaEntityController::load(). Then, it's not a case like:

Load 5000 pieces of media
iterate through each one
call a function on each one to determine access
Return 3.

We can do uid and type easily in the ->load() method. "stream" could also be done with a LIKE condition.

JacobSingh’s picture

Look at entity.inc in buildQuery() This is where the condition "magic" is happening. Most likely, we would want to implement load(), copy what is there currently, but after buildQuery, add permissions logic to the query if that module is enabled.

aaron’s picture

@jacob: this all sounds good. the code in there was in there before; i just reshuffled it a bit. i'm not attached to that, and think your approach is more sound.

james.elliott’s picture

Title: Granualar editorial control access » Filenames for private files are viewable for non-privileged users
Category: task » bug
Priority: Critical » Major

Tested this and thumbnails are not shown, only filename is visible.

effulgentsia’s picture

Title: Filenames for private files are viewable for non-privileged users » Granular editorial access control
Category: bug » feature
Priority: Major » Normal
StatusFileSize
new2.24 KB

I committed this patch to CVS HEAD to address #2/#10. This is good enough for a 1.0 release, IMO. A better access control system would be awesome though, so if anyone feels like working on that, ++!

mrfree’s picture

In my case I'd like to restrict available/selectable media in the media gallery to those uploaded creating a specific content type.

I mean... if I upload an image creating content "cntfoo_1", I don't want to see that image in the gallery I can browse when I create a content "cntfoo_2" because it's useless in my case (and sometimes should be denied because of private content for example)

What's your opinion?
I think it isn't achievable at the moment...

robeano’s picture

It's great to see this patch in place. Thanks effulgentsia!

Using 'administer media' is a bit extreme. I have a scenario where folks need access to private files but should not have access to configure the media module settings.

Perhaps we could use a different permission to check? I would like to think that someone who can edit media could upload/view private files. Could we change it to 'edit media' or should there be a new permission for this sort of thing? 'private media' perhaps?

I'm happy to commit that change, but just wanted to get some confirmation first.

aaron’s picture

how about we simply check hook_file_download to see if they're able to access private files? http://api.drupal.org/api/drupal/modules--system--system.api.php/functio...

aaron’s picture

in fact, the nice thing about that approach is it would allow, for instance, certain youtube videos to be marked as private as well, and for alternative private schemes. this is how core handles it, afaik.

jazzslider’s picture

Version: » 7.x-2.0-unstable1

The solution currently in place also makes it impossible to allow read-only access to the information on those media/* pages. For example: I have a site that stores lots of image files, all of which have "private://" paths to keep them from being downloaded by unprivileged users. I'm also leveraging file_entity to add useful fields to the image file type, and the only place that information is exposed is on the media/* page for each file. Unfortunately, since the only users who can see media/* pages for private:// files are users with "administer media", I can't grant users the right to view those pages without also granting them the right to deface them.

I'm with robeano on this one; we need a permission other than "administer media" for this to work correctly.

Thanks!
Adam

aaron’s picture

Version: 7.x-2.0-unstable1 » 7.x-2.x-dev

@jazzslider: actually, there's a 'view media' permission ('View all media files') that does just what you want already in the 7.x-2.x branch.

bryancasler’s picture

subscribe

bryancasler’s picture

Has this conversation now shifted to #1227706: Add a file entity access API ?

dave reid’s picture

Status: Needs work » Closed (duplicate)

Yes, let's mark this as a duplicate of #1227706: Add a file entity access API.