class Aws::CF::Signer

Attributes

default_expires[W]

Public: Provides a configuration option that sets the default_expires in milliseconds

Examples

Aws::CF::Signer.configure do |config|
  config.default_expires = 3600
end

Returns nothing.

key_pair_id[RW]

Public: Provides a configuration option to set the key_pair_id if it has not been inferred from the key_path

Examples

Aws::CF::Signer.configure do |config|
  config.key_pair_id = "XXYYZZ"
end

Returns a String value indicating the current setting

key_path[R]

Public: Provides an accessor to the key_path

Returns a String value indicating the current setting

Public Class Methods

build_url(original_subject, configuration_options = {}, policy_options = {}) click to toggle source

Public: Builds a signed url or stream resource name with optional configuration and policy options

Returns a String

# File lib/cloudfront-signer.rb, line 180
def self.build_url(original_subject, configuration_options = {}, policy_options = {})
  subject = original_subject.dup
  # If the url or stream path already has a query string parameter -
  # append to that.
  separator = subject =~ /\?/ ? '&' : '?'

  subject.gsub!(/\s/, '%20') if configuration_options[:remove_spaces]
  subject = URI.escape(subject) if configuration_options[:uri_escape]

  result = subject +
           separator +
           signed_params(subject, policy_options).collect do |key, value|
             "#{key}=#{value}"
           end.join('&')

  if configuration_options[:html_escape]
    return html_encode(result)
  else
    return result
  end
end
configure() { |self| ... } click to toggle source

Public: Provides a simple way to configure the signing class.

Yields self.

Examples

Aws::CF::Signer.configure do |config|
  config.key_path = "/path/to/yourkeyfile.pem"
  config.key_pair_id  = "XXYYZZ"
  config.default_expires = 3600
end

Returns nothing.

# File lib/cloudfront-signer.rb, line 104
def self.configure
  yield self if block_given?

  unless key_path || private_key
    fail ArgumentError,
         'You must supply the path to a PEM format RSA key pair.'
  end

  unless @key_pair_id
    @key_pair_id = extract_key_pair_id(key_path)
    fail ArgumentError,
         'The Cloudfront signing key id could not be inferred from ' \
         "#{key_path}. Please supply the key pair id as a " \
         'configuration argument.' unless @key_pair_id
  end
end
default_expires() click to toggle source

Public: Provides an accessor to the default_expires value

Returns an Integer value indicating the current setting

# File lib/cloudfront-signer.rb, line 77
def default_expires
  @default_expires ||= 3600
end
is_configured?() click to toggle source

Public: Provides a configuration check method which tests to see that the key_path, key_pair_id and private key values have all been set.

Returns a Boolean value indicating that settings are present.

# File lib/cloudfront-signer.rb, line 125
def self.is_configured?
  (key_pair_id.nil? || private_key.nil?) ? false : true
end
key=(key) click to toggle source

Public: Provides a configuration option to set the key directly as a string e.g. as an ENV var

Examples

Aws::CF::Signer.configure do |config|
  config.key = ENV.fetch('KEY')
end

Returns nothing.

# File lib/cloudfront-signer.rb, line 53
def key=(key)
  @key = OpenSSL::PKey::RSA.new(key)
end
key_path=(path) click to toggle source

Public: Provides a configuration option that sets the key_path

Examples

Aws::CF::Signer.configure do |config|
  config.key_path = "/path/to/your/keyfile.pem"
end

Returns nothing.

# File lib/cloudfront-signer.rb, line 35
def key_path=(path)
  unless File.exist?(path)
    fail ArgumentError,
         "The signing key could not be found at #{path}"
  end
  @key_path = path
  self.key = File.readlines(path).join('')
end
sign_path(subject, policy_options = {}) click to toggle source

Public: Sign a stream path part or filename (spaces are allowed in stream paths and so are not removed).

Returns a String

# File lib/cloudfront-signer.rb, line 156
def self.sign_path(subject, policy_options = {})
  build_url subject, { remove_spaces: false }, policy_options
end
sign_path_escaped(subject, policy_options = {}) click to toggle source

Public: Sign a stream path or filename but URI encode the string first

Returns a String

# File lib/cloudfront-signer.rb, line 172
def self.sign_path_escaped(subject, policy_options = {})
  build_url subject, { uri_escape: true }, policy_options
end
sign_path_safe(subject, policy_options = {}) click to toggle source

Public: Sign a stream path or filename and HTML encode the result.

Returns a String

# File lib/cloudfront-signer.rb, line 163
def self.sign_path_safe(subject, policy_options = {})
  build_url subject,
            { remove_spaces: false, html_escape: true },
            policy_options
end
sign_url(subject, policy_options = {}) click to toggle source

Public: Sign a url - encoding any spaces in the url before signing. CloudFront stipulates that signed URLs must not contain spaces (as opposed to stream paths/filenames which CAN contain spaces).

Returns a String

# File lib/cloudfront-signer.rb, line 134
def self.sign_url(subject, policy_options = {})
  build_url subject, { remove_spaces: true }, policy_options
end
sign_url_escaped(subject, policy_options = {}) click to toggle source

Public: Sign a url (as above) but URI encode the string first.

Returns a String

# File lib/cloudfront-signer.rb, line 148
def self.sign_url_escaped(subject, policy_options = {})
  build_url subject, { uri_escape: true }, policy_options
end
sign_url_safe(subject, policy_options = {}) click to toggle source

Public: Sign a url (as above) and HTML encode the result.

Returns a String

# File lib/cloudfront-signer.rb, line 141
def self.sign_url_safe(subject, policy_options = {})
  build_url subject, { remove_spaces: true, html_escape: true }, policy_options
end
signed_params(subject, policy_options = {}) click to toggle source

Public: Sign a subject url or stream resource name with optional policy options. It returns raw params to be used in urls or cookies

Returns a Hash

# File lib/cloudfront-signer.rb, line 206
def self.signed_params(subject, policy_options = {})
  result = {}

  if policy_options[:policy_file]
    policy = IO.read(policy_options[:policy_file])
    result['Policy'] = encode_policy(policy)
  else
    policy_options[:expires] = epoch_time(policy_options[:expires] ||
                                          Time.now + default_expires)

    if policy_options.keys.size <= 1
      # Canned Policy - shorter URL
      expires_at = policy_options[:expires]
      policy = %{{"Statement":[{"Resource":"#{subject}","Condition":{"DateLessThan":{"AWS:EpochTime":#{expires_at}}}}]}}
      result['Expires'] = expires_at
    else
      # Custom Policy
      resource = policy_options[:resource] || subject
      policy = generate_custom_policy(resource, policy_options)
      result['Policy'] = encode_policy(policy)
    end
  end

  result.merge 'Signature' => create_signature(policy),
               'Key-Pair-Id' => @key_pair_id
end

Private Class Methods

create_signature(policy) click to toggle source
# File lib/cloudfront-signer.rb, line 273
def self.create_signature(policy)
  url_encode Base64.encode64(
    private_key.sign(OpenSSL::Digest::SHA1.new, (policy))
  )
end
encode_policy(policy) click to toggle source
# File lib/cloudfront-signer.rb, line 269
def self.encode_policy(policy)
  url_encode Base64.encode64(policy)
end
epoch_time(timelike) click to toggle source
# File lib/cloudfront-signer.rb, line 258
def self.epoch_time(timelike)
  case timelike
  when String then Time.parse(timelike).to_i
  when Time   then timelike.to_i
  when Integer then timelike
  else fail ArgumentError,
            'Invalid argument - String, Integer or Time required - ' \
            "#{timelike.class} passed."
  end
end
extract_key_pair_id(key_path) click to toggle source
# File lib/cloudfront-signer.rb, line 279
def self.extract_key_pair_id(key_path)
  File.basename(key_path) =~ /^pk-(.*).pem$/ ? Regexp.last_match[1] : nil
end
generate_custom_policy(resource, options) click to toggle source
# File lib/cloudfront-signer.rb, line 235
def self.generate_custom_policy(resource, options)
  conditions = {
    'DateLessThan' => {
      'AWS:EpochTime' => epoch_time(options[:expires])
    }
  }

  conditions['DateGreaterThan'] = {
    'AWS:EpochTime' => epoch_time(options[:starting])
  } if options[:starting]

  conditions['IpAddress'] = {
    'AWS:SourceIp' => options[:ip_range]
  } if options[:ip_range]

  {
    'Statement' => [{
      'Resource' => resource,
      'Condition' => conditions
    }]
  }.to_json
end
html_encode(s) click to toggle source
# File lib/cloudfront-signer.rb, line 288
def self.html_encode(s)
  s.gsub('?', '%3F').gsub('=', '%3D').gsub('&', '%26')
end
private_key() click to toggle source

Private: Provides an accessor to the RSA key value

Returns an RSA key pair.

# File lib/cloudfront-signer.rb, line 86
def private_key
  @key
end
url_encode(s) click to toggle source
# File lib/cloudfront-signer.rb, line 283
def self.url_encode(s)
  s.gsub('+', '-').gsub('=', '_').gsub('/', '~').gsub(/\n/, '')
    .gsub(' ', '')
end