Class: AwsCfSigner

Inherits:
Object
  • Object
show all
Defined in:
lib/aws_cf_signer.rb,
lib/aws_cf_signer/version.rb

Constant Summary collapse

VERSION =
"0.1.2"

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(pem_path, key_pair_id = nil) ⇒ AwsCfSigner

Returns a new instance of AwsCfSigner.



9
10
11
12
13
14
15
16
# File 'lib/aws_cf_signer.rb', line 9

def initialize(pem_path, key_pair_id = nil)
  @pem_path    = pem_path
  @key         = OpenSSL::PKey::RSA.new(File.readlines(@pem_path).join(""))
  @key_pair_id = key_pair_id ? key_pair_id : extract_key_pair_id(@pem_path)
  unless @key_pair_id
    raise ArgumentError.new("key_pair_id couldn't be inferred from #{@pem_path} - please pass in explicitly")
  end
end

Instance Attribute Details

#key_pair_idObject (readonly)

Returns the value of attribute key_pair_id.



7
8
9
# File 'lib/aws_cf_signer.rb', line 7

def key_pair_id
  @key_pair_id
end

Instance Method Details

#create_signature(policy) ⇒ Object



58
59
60
# File 'lib/aws_cf_signer.rb', line 58

def create_signature(policy)
  url_safe(Base64.encode64(@key.sign(OpenSSL::Digest::SHA1.new, (policy))))
end

#encode_policy(policy) ⇒ Object



54
55
56
# File 'lib/aws_cf_signer.rb', line 54

def encode_policy(policy)
  url_safe(Base64.encode64(policy))
end

#epoch_time(timelike) ⇒ Object



46
47
48
49
50
51
52
# File 'lib/aws_cf_signer.rb', line 46

def epoch_time(timelike)
  case timelike
  when String then Time.parse(timelike).to_i
  when Time   then timelike.to_i
  else raise ArgumentError.new("Invalid argument - String or Time required - #{timelike.class} passed.")
  end
end

#extract_key_pair_id(key_path) ⇒ Object



62
63
64
# File 'lib/aws_cf_signer.rb', line 62

def extract_key_pair_id(key_path)
  File.basename(key_path) =~ /^pk-(.*).pem$/ ? $1 : nil
end

#generate_custom_policy(resource, options) ⇒ Object



39
40
41
42
43
44
# File 'lib/aws_cf_signer.rb', line 39

def generate_custom_policy(resource, options)
  conditions = ["\"DateLessThan\":{\"AWS:EpochTime\":#{epoch_time(options[:ending])}}"]
  conditions << "\"DateGreaterThan\":{\"AWS:EpochTime\":#{epoch_time(options[:starting])}}" if options[:starting]
  conditions << "\"IpAddress\":{\"AWS:SourceIp\":\"#{options[:ip_range] || '0.0.0.0/0'}\""
  %({"Statement":[{"Resource":"#{resource}","Condition":{#{conditions.join(',')}}}}]})
end

#sign(url_to_sign, policy_options = {}) ⇒ Object



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/aws_cf_signer.rb', line 18

def sign(url_to_sign, policy_options = {})
  separator = url_to_sign =~ /\?/ ? '&' : '?'
  if policy_options[:policy_file]
    policy = IO.read(policy_options[:policy_file])
    "#{url_to_sign}#{separator}Policy=#{encode_policy(policy)}&Signature=#{create_signature(policy)}&Key-Pair-Id=#{@key_pair_id}"
  else
    raise ArgumentError.new("'ending' argument is required") if policy_options[:ending].nil?
    if policy_options.keys == [:ending] || policy_options.keys.sort == [:ending, :resource]
      # Canned Policy - shorter URL
      expires_at = epoch_time(policy_options[:ending])
      policy = %({"Statement":[{"Resource":"#{policy_options[:resource] || url_to_sign}","Condition":{"DateLessThan":{"AWS:EpochTime":#{expires_at}}}}]})
      "#{url_to_sign}#{separator}Expires=#{expires_at}&Signature=#{create_signature(policy)}&Key-Pair-Id=#{@key_pair_id}"
    else
      # Custom Policy
      resource = policy_options[:resource] || url_to_sign
      policy = generate_custom_policy(resource, policy_options)
      "#{url_to_sign}#{separator}Policy=#{encode_policy(policy)}&Signature=#{create_signature(policy)}&Key-Pair-Id=#{@key_pair_id}"
    end
  end
end

#url_safe(s) ⇒ Object



66
67
68
# File 'lib/aws_cf_signer.rb', line 66

def url_safe(s)
  s.gsub('+','-').gsub('=','_').gsub('/','~').gsub(/\n/,'').gsub(' ','')
end