Last active
January 1, 2016 14:29
-
-
Save itskingori/8157675 to your computer and use it in GitHub Desktop.
Use a canned policy to create a CloudFront signed URL in Rails (slight modification required for plain Ruby) ... includes method to create a download attachment URL as well (this one requires bucket and distribution configuration) i.e. using content disposition header with attachment
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Helper | |
def self.get_url_using_canned_policy(url, expires_in = 300) | |
# The date and time, in Unix time format (in seconds) and Coordinated | |
# Universal Time (UTC), that you want the URL to stop allowing access to | |
# the object. For example, January 1, 2013 10:00 am UTC converts to | |
# 1357034400 in Unix time format. For information about UTC, see RFC 3339, | |
# Date and Time on the Internet: Timestamps, | |
# http://tools.ietf.org/html/rfc3339. | |
expires = (Time.now.utc + expires_in).to_i | |
key_pair_id = 'YOUR_KEY_PAIR_ID' | |
# This policy is well known by CloudFront, but we still need to sign it, since it contains our parameters | |
policy = %Q[{"Statement":[{"Resource":"#{url}","Condition":{"DateLessThan":{"AWS:EpochTime":#{expires}}}}]}] | |
# The signature is a hashed and signed version of the policy statement. | |
# The policy contains characters that cannot be part of a URL, so we | |
# Base64 encode it to create a URL-safe version of the signature. | |
private_key = OpenSSL::PKey::RSA.new(File.read(Rails.root.join('config', 'certs', 'pk-XXXXXXXXXXXXXXXXXXX.pem'))) | |
signature = Base64.strict_encode64(private_key.sign(OpenSSL::Digest::SHA1.new, policy)) | |
signature.tr!('+=/', '-_~') | |
"#{url}?Expires=#{expires}&Signature=#{signature}&Key-Pair-Id=#{key_pair_id}" | |
end | |
# Use a canned policy to create a CloudFront signed download URL (e.g. attachments) | |
def self.get_download_url_using_canned_policy(url, desired_download_filename,expires_in = 300) | |
# all parameter names and values are escaped using the [rfc3986] percent- | |
# encoding (%xx) mechanism. characters not in the unreserved character set | |
# ([rfc3986] section 2.3) must be encoded. characters in the unreserved | |
# character set must not be encoded. hexadecimal characters in encodings | |
# must be upper case. text names and values must be encoded as utf-8 octets | |
# before percent-encoding them per [rfc3629]. | |
# reserved character regexp, per section 5.1 | |
reserved_characters = /[^a-zA-Z0-9\-\.\_\~]/ | |
# You must do the following; | |
# 1) Configure your download streaming distribution behaviour to forward query strings | |
# 2) Restrict bucket access and grant CF read permissions on the bucket | |
# For more information read; | |
# 1) http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/QueryStringParameters.html | |
# 2) https://forums.aws.amazon.com/thread.jspa?messageID=421768# | |
# Example construct url (removed some characters & double spaces just to be safe); | |
# https://abcdefgxyz.cloundfront.net/filename.ext?response-content-disposition=<attachment|inline>;filename=<utf8 and urlencoded desired filename>&response-content-type=<Mimetype> | |
header = URI.escape %Q[attachment;filename="#{desired_download_filename.gsub(/[^\w'. ]/, '').gsub(/\s+/, ' ')}"], reserved_characters | |
url << "?response-content-disposition=#{header}" | |
# This part is the same as above so just refer to comments in the | |
# get_url_using_canned_policy method to know what's going on | |
expires = (Time.now.utc + expires_in).to_i | |
key_pair_id = 'YOUR_KEY_PAIR_ID' | |
policy = %Q[{"Statement":[{"Resource":"#{url}","Condition":{"DateLessThan":{"AWS:EpochTime":#{expires}}}}]}] | |
private_key = OpenSSL::PKey::RSA.new(File.read(Rails.root.join('config', 'certs', 'pk-XXXXXXXXXXXXXXXXXXX.pem'))) | |
signature = Base64.strict_encode64(private_key.sign(OpenSSL::Digest::SHA1.new, policy)) | |
signature.tr!('+=/', '-_~') | |
"#{url}&Expires=#{expires}&Signature=#{signature}&Key-Pair-Id=#{key_pair_id}" | |
end | |
end | |
# Call something like ... Helper.get_url_using_canned_policy(url, seconds) | |
# Assumes keyfile is in RAILS_ROOT/config/certs ... change if you wanna | |
# Thanks to https://gist.github.com/iHiD/955355 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment