Plugins - FilePermissions
Add to favoritesFilePermissions
Use this plugin if you want to fine-tune permissions on some or all the files in your public directory.
Normally these files are served by the webserver before Rails ever gets a chance to see the request. This plugin tells the webserver to pass certain file requests on to Rails, where a before_filter intercepts them and passes them to a callback you provide to determine whether you would like to serve them or not. It provides a handy controller method that lets you serve the file efficiently, complete with flexible cache-control support.
Example
You can register the files you are interested in anywhere, really, but it probably makes the most sense to put it in app/controllers/application.rb, together with the before_filter, so that it’s all in one place:
class ApplicationController < ActionController::Base
# Make sure we've had a chance to login the user, first, if we support
# "remember-me" style login via cookies.
before_filter :autologin
# Now intercept file requests and evaluate permissions.
before_filter :file_permissions
# Simplest example: just check if the current user has permission to see
# a given file. It serves the file automatically if you return true,
# otherwise it renders /public/403.html (this is not supplied with Rails).
FilePermissions.register("/public/images/user") do |controller, file|
controller.session[:user].has_permission_to_view_image(file)
end
# You may customize things very easily: This time we look up the Image
# object associated with our images, query a database to see if the current
# user has access. If they do, render it, but instruct the browser to keep
# the image in a private cache, and tell it to revalidate once a day. If
# the user does not have access, render the "access_denied" view.
FilePermissions.register(/public.images.user.(\d+).jpg$/) do |controller, file, match|
if (img = Image.find(match[1])) &&
img.can_user_see_me?(controller.session[:user])
controller.render_file(file,
:private => true,
:max_age => 1.day,
:must_revalidate => true
)
else
controller.render(:action => "access_denied")
end
end
end
Limitations
Currently it only works with Mongrel. But it should be relatively easy to hack Webrick or any other Ruby webservers the same way we’ve done Mongrel.
You will need to make sure there is a route defined for the files you are protecting. I recommend something like what’s shown below to capture everything under a given directory. Remember, it doesn’t actually ever reach the bogus action. In fact, even the controller is unimportant if you place before_filter :file_permissions in ApplicationController.
ActionController::Routing::Routes.draw do |map|
# Route everything under /images to "anycontroller".
map.connect "/images/*file", :controller => "anycontroller", :action => "bogus"
end
If you are running Mongrel under Apache, then you will further need to instruct Apache to pass these files. Typically this is done in the configuration file using ProxyPass directives. For example, a typical configuration might look like this:
<VirtualHost *:80>
ServerName yourdomain.com
DocumentRoot "/usr/local/rails/yourdomain"
SetEnv RAILS_ENV production
<Directory /usr/local/rails/yourdomain>
Options FollowSymLinks
AllowOverride AuthConfig Limit
Order allow,deny
Allow from all
</Directory>
# Tell Apache to pass requests for user images on to Rails.
ProxyPass /images/user balancer://mongrel_cluster/
# Everything else in public is okay to serve up as-is.
ProxyPass /images !
ProxyPass /stylesheets !
ProxyPass /javascripts !
ProxyPass /robots.txt !
ProxyPass /favicon.ico !
# Everything else goes to Rails.
ProxyPass / balancer://mongrel_cluster/
ProxyPreserveHost on
<Proxy balancer://mongrel_cluster>
BalancerMember http://127.0.0.1:3000
BalancerMember http://127.0.0.1:3001
BalancerMember http://127.0.0.1:3002
</Proxy>
RewriteEngine on
etc...
</VirtualHost>
| Author: | Jason Hollinger |
| License: | Free - do whatever you want to with it. |
| Last Update: | July 30, 2008 |
