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.3"

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(key_or_pem_path, key_pair_id = nil) ⇒ AwsCfSigner

Returns a new instance of AwsCfSigner.



9
10
11
12
13
14
15
16
17
18
19
20
21
# File 'lib/aws_cf_signer.rb', line 9

def initialize(key_or_pem_path, key_pair_id = nil)
  if key_or_pem_path =~ /BEGIN RSA PRIVATE KEY/
    @key = OpenSSL::PKey::RSA.new(key_or_pem_path)
    @key_pair_id = key_pair_id or raise ArgumentError, "key_pair_id could not be inferred - please pass in explicitly"
  else
    @pem_path    = key_or_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
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



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

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

#encode_policy(policy) ⇒ Object



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

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

#epoch_time(timelike) ⇒ Object



51
52
53
54
55
56
57
# File 'lib/aws_cf_signer.rb', line 51

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



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

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

#generate_custom_policy(resource, options) ⇒ Object



44
45
46
47
48
49
# File 'lib/aws_cf_signer.rb', line 44

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



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/aws_cf_signer.rb', line 23

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



71
72
73
# File 'lib/aws_cf_signer.rb', line 71

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