class Aws::CloudFront::UrlSigner

Allows you to create signed URLs for Amazon CloudFront resources

signer = Aws::CloudFront::UrlSigner.new
url = signer.signed_url(url,
  key_pair_id: "cf-keypair-id",
  private_key_path: "./cf_private_key.pem"
)

Public Class Methods

new(options = {}) click to toggle source

@option options [String] :key_pair_id @option options [String] :private_key @option options [String] :private_key_path

# File lib/aws-sdk-core/cloudfront/url_signer.rb, line 23
def initialize(options = {})
  @key_pair_id = key_pair_id(options)
  @private_key = private_key(options)
end

Public Instance Methods

signed_url(url, params = {}) click to toggle source

create a signed Amazon CloudFront URL @param [String] url @option params [Time, DateTime, Date, String, Integer<timestamp>] :expires @option params [String<JSON>] :policy

# File lib/aws-sdk-core/cloudfront/url_signer.rb, line 32
def signed_url(url, params = {})
  url_sections = url.split('://')
  if url_sections.length < 2
    raise ArgumentError, "Invaild URL:#{url}"
  end
  # removing wildcard character to get real scheme
  scheme = url_sections[0].gsub('*', '')
  uri = "#{scheme}://#{url_sections[1]}"
  signed_content = signature(
    :resource => resource(scheme, uri),
    :expires => time(params[:expires]),
    :policy => params[:policy]
  )

  start_flag = URI.parse(uri).query ? '&' : '?'
  uri = "#{uri}#{start_flag}#{signed_content}"

  if scheme == 'rtmp'
    rtmp_url(URI(uri))
  else
    uri
  end
end

Private Instance Methods

canned_policy(resource, expires) click to toggle source

create canned policy that used for signing

# File lib/aws-sdk-core/cloudfront/url_signer.rb, line 130
def canned_policy(resource, expires)
  json_hash = {
    'Statement' => [
      'Resource' => resource,
        'Condition' => {
          'DateLessThan' => {'AWS:EpochTime' => expires}
        }
    ]
  }
  json_hash.to_json
end
encode(policy) click to toggle source
# File lib/aws-sdk-core/cloudfront/url_signer.rb, line 142
def encode(policy)
  Base64.encode64(policy).gsub(/[+=\/]/, '+' => '-', '=' => '_', '/' => '~')
end
key_pair_id(options) click to toggle source
# File lib/aws-sdk-core/cloudfront/url_signer.rb, line 146
def key_pair_id(options)
  if options[:key_pair_id].nil? or options[:key_pair_id] == ''
    raise ArgumentError, ":key_pair_id must not be blank"
  else
    options[:key_pair_id]
  end
end
private_key(options) click to toggle source
# File lib/aws-sdk-core/cloudfront/url_signer.rb, line 154
def private_key(options)
  if options[:private_key]
    options[:private_key]
  elsif options[:private_key_path]
    File.open(options[:private_key_path], 'rb') { |f| f.read }
  else
    msg = ":private_key or :private_key_path should be provided"
    raise ArgumentError, msg
  end
end
resource(scheme, url) click to toggle source

prepare resource for signing

# File lib/aws-sdk-core/cloudfront/url_signer.rb, line 82
def resource(scheme, url)
  case scheme
  when 'http', 'http*', 'https' then url
  when 'rtmp'
    url_info = URI.parse(url)
    path = url_info.path
    path[0] = ''
    resource_content = "#{File.dirname(path)}/#{File.basename(path)}".gsub(' ', '/')
    if url_info.query
      "#{resource_content}?#{uri.query}"
    else
      resource_content
    end
  else
    msg = "Invaild URI scheme:#{scheme}.Scheme must be one of: http, https or rtmp."
    raise ArgumentError, msg
  end
end
rtmp_url(uri) click to toggle source

create a relative signed URL for RTMP distribution

# File lib/aws-sdk-core/cloudfront/url_signer.rb, line 71
def rtmp_url(uri)
  result = uri.path.gsub(' ', '/')
  result[0] = ''
  if uri.query
    "#{result}?#{uri.query}"
  else
    result
  end
end
sign_policy(policy) click to toggle source

create the signature string with policy signed

# File lib/aws-sdk-core/cloudfront/url_signer.rb, line 124
def sign_policy(policy)
  key = OpenSSL::PKey::RSA.new(@private_key)
  key.sign(OpenSSL::Digest::SHA1.new, policy)
end
signature(params = {}) click to toggle source

create signed values that used to construct signed URLs @option param [String] :resource @option param [Integer<timestamp>] :expires @option param [String<JSON>] :policy

# File lib/aws-sdk-core/cloudfront/url_signer.rb, line 105
def signature(params = {})
  signature_content = []
  if params[:policy]
    policy = params[:policy].gsub('/\s/s', '')
    signature_content << "Policy=#{encode(policy)}"
  elsif params[:resource] && params[:expires]
    policy = canned_policy(params[:resource], params[:expires])
    signature_content << "Expires=#{params[:expires]}"
  else
    msg = "Either a policy or a resource with an expiration time must be provided."
    raise ArgumentError, msg
  end

  signature_content << "Signature=#{encode(sign_policy(policy))}"
  signature_content << "Key-Pair-Id=#{@key_pair_id}"
  signature_content.join('&').gsub("\n", '')
end
time(expires) click to toggle source
# File lib/aws-sdk-core/cloudfront/url_signer.rb, line 58
def time(expires)
  case expires
  when Time then expires.to_i
  when DateTime, Date then expires.to_time.to_i
  when String then Time.parse(expires).to_i
  when Integer, NIL then expires
  else
    msg = "expected a time value for :expires, got `#{expires.class}'"
    raise ArgumentError, msg
  end
end