-
-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Restricting Access to Objects Stored on Amazon S3
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).
Restricting access can be a bit tricky. It’s easy enough to have Paperclip mark your file as private when you store it on S3, but when it comes time to serve the file, its private status means the client won’t be able to get it directly from S3. Typically, you’ll resolve this by proxying the download via your own app, i.e. the request-response cycle looks like this: client/browser/app -> Rails -> S3 -> Rails -> client/browser/app. Setting up access control is therefore a three step process:
-
S3 storage
has_attached_file :annual_report, :storage => :s3, :s3_credentials => "#{Rails.root}/config/s3.yml", :s3_permissions => :private, :path => "photos/:id/:filename"
-
FOG storage
has_attached_file :lib, storage: :fog, fog_credentials: { provider: 'AWS', aws_access_key_id: Rails.application.secrets.aws_access_key, aws_secret_access_key: Rails.application.secrets.aws_secret_access_key, region: 'region', scheme: 'https' }, fog_directory: 'bucket_name', fog_options: { multipart_chunk_size: 10.megabytes }, fog_host: nil, fog_public: false, path: "photos/:id/:filename"
At this point, any uploaded annual_reports
should be inaccessible.
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) %>
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 CanCanCan.