Restricting Access to Objects Stored on Amazon S3

Joel Courtney edited this page Nov 17, 2016 · 9 revisions

How permissions work by default.

By default paperclip sets permissions for all AS3 uploads as :public_read ('public-read' in v5.0+). This means your files are totally wide open (i.e. they can be accessed by anyone simply by pasting the AS3 url into the browser).

What if you need to restrict access?

Restricting access can seem a bit tricky since Amazon – rather than your app – is serving the assets. It's a three step process:

1. Set :s3_permissions to :private in your paperclip model:

has_attached_file :annual_report,
 :storage => :s3,
 :s3_credentials => "#{Rails.root}/config/s3.yml",
 :s3_permissions => :private,
 :path => "photos/:id/:filename"

At this point, any uploaded annual_reports should be inaccessible.

2. Create a download action in your controller:

def download
  redirect_to @department.annual_report.expiring_url(10)
end

This action simply catches the request and redirects to the AS3 url. But notice the expiring_url method call. This is where the magic happens. The method creates a temporarily authenticated url set to expire after 10 seconds. Now the only way to access the annual_report is through the download action. Note: If you are using fog as your provider, pass the expiration time rather than the number of seconds until the url expires, i.e. Time.now + 10.seconds.

Assuming you've set things up correctly (don't forget about routing), you can now use this action in your views:

<%= link_to "View Annual Report", download_annual_report_path(@department) %>

3. Setup authorization for the download action

Not worth going into details here. But most solutions would involve some kind of before_filter which checks if the current user is allowed to download the file in question. If your authorization requirements are at all complicated I would suggest checking out CanCan.

Other helpful links