class EC2::Common::HeadersV4

Public Class Methods

hexdigest(value, chunk_size = 1024 * 1024) click to toggle source

Returns a SHA256 hexdigest of value. Should be used to hexdigest body of http request.

# File lib/ec2/common/headersv4.rb, line 160
def self.hexdigest value, chunk_size = 1024 * 1024
  digest = Digest::SHA256.new
  if value.respond_to?(:read)
    chunk = nil
    digest.update(chunk) while chunk = value.read(chunk_size)
    value.rewind
  else
    digest.update(value)
  end
  digest.hexdigest
end
new(values, headers={}) click to toggle source

Create an HttpHeaderV4, values = {

:host -> http host
:hexdigest_body -> hexdigest of the http request's body
:region -> region of the endpoint
:service -> the service that should recieve this request
:http_method -> http method
:path -> URI
:querystring -> Everything after ? in URI
:access_key_id -> access key
:secret_access_key -> secret access kry
[optional] :fixed_datetime -> Fix the datetime using DateTime object, do not use Time.now

} For more info see: docs.aws.amazon.com/general/latest/gr/signature-version-4.html

# File lib/ec2/common/headersv4.rb, line 44
def initialize values, headers={}
  @headers = headers
  @host = values[:host]
  @hexdigest_body = values[:hexdigest_body]
  @region = values[:region]
  @service = values[:service]
  @http_method = values[:http_method]
  @path = values[:path]
  @querystring = values[:querystring]
  @access_key_id = values[:access_key_id]
  @secret_access_key = values[:secret_access_key]
  @fixed_datetime = values[:fixed_datetime]
end

Public Instance Methods

add_authorization!() click to toggle source
# File lib/ec2/common/headersv4.rb, line 58
def add_authorization!
  datetime = get_datetime
  @headers['host'] = @host
  @headers['x-amz-date'] = datetime
  @headers['x-amz-content-sha256'] ||= @hexdigest_body || EC2::Common::HeadersV4::hexdigest('')
  @headers['authorization'] = authorization(datetime)
  @headers
end
authorization(datetime) click to toggle source
# File lib/ec2/common/headersv4.rb, line 67
def authorization datetime
  parts = []
  parts << "AWS4-HMAC-SHA256 Credential=#{credential(datetime)}"
  parts << "SignedHeaders=#{signed_headers}"
  parts << "Signature=#{signature(datetime)}"
  parts.join(', ')
end
canonical_header_values(values) click to toggle source
# File lib/ec2/common/headersv4.rb, line 140
def canonical_header_values values
  values = [values] unless values.is_a?(Array)
  values.map{|v|v.to_s}.join(',').gsub(/\s+/, ' ').strip
end
canonical_headers() click to toggle source
# File lib/ec2/common/headersv4.rb, line 130
def canonical_headers
  headers = []
  @headers.each_pair do |k,v|
    k_lower = k.downcase
    headers << [k_lower,v] unless k_lower == 'authorization'
  end
  headers = headers.sort_by{|k,v| k}
  headers.map{|k,v| "#{k}:#{canonical_header_values(v)}"}.join("\n")
end
canonical_querystring() click to toggle source
# File lib/ec2/common/headersv4.rb, line 123
def canonical_querystring
  CGI::parse(@querystring).sort_by{|k,v| CGI::escape(k)}.map do |v|
    value = v[1][0] || ""
    "#{CGI::escape(v[0])}=#{CGI::escape(value)}"
  end.join('&')
end
canonical_request() click to toggle source
# File lib/ec2/common/headersv4.rb, line 106
def canonical_request
  parts = []
  parts << @http_method
  parts << CGI::unescape(@path)
  parts << canonical_querystring
  parts << canonical_headers + "\n"
  parts << signed_headers
  parts << @headers['x-amz-content-sha256']
  parts.join("\n")
end
credential(datetime) click to toggle source
# File lib/ec2/common/headersv4.rb, line 93
def credential datetime
  "#{@access_key_id}/#{credential_string(datetime)}"
end
credential_string(datetime) click to toggle source
# File lib/ec2/common/headersv4.rb, line 97
def credential_string datetime
  parts = []
  parts << datetime[0,8]
  parts << @region
  parts << @service
  parts << 'aws4_request'
  parts.join("/")
end
get_datetime() click to toggle source
# File lib/ec2/common/headersv4.rb, line 153
def get_datetime
  return @fixed_datetime.strftime("%Y%m%dT%H%M%SZ") if @fixed_datetime != nil
  Time.now.utc.strftime("%Y%m%dT%H%M%SZ")
end
hexhmac(key, value) click to toggle source
# File lib/ec2/common/headersv4.rb, line 149
def hexhmac key, value
  OpenSSL::HMAC.hexdigest(OpenSSL::Digest::Digest.new('sha256'), key, value)
end
hmac(key, value) click to toggle source
# File lib/ec2/common/headersv4.rb, line 145
def hmac key, value
  OpenSSL::HMAC.digest(OpenSSL::Digest::Digest.new('sha256'), key, value)
end
signature(datetime) click to toggle source
# File lib/ec2/common/headersv4.rb, line 75
def signature datetime
  k_secret = @secret_access_key
  k_date = hmac("AWS4" + k_secret, datetime[0,8])
  k_region = hmac(k_date, @region)
  k_service = hmac(k_region, @service)
  k_credentials = hmac(k_service, 'aws4_request')
  hexhmac(k_credentials, string_to_sign(datetime))
end
signed_headers() click to toggle source
# File lib/ec2/common/headersv4.rb, line 117
def signed_headers
  to_sign = @headers.keys.map{|k| k.to_s.downcase}
  to_sign.delete('authorization')
  to_sign.sort.join(";")
end
string_to_sign(datetime) click to toggle source
# File lib/ec2/common/headersv4.rb, line 84
def string_to_sign datetime
  parts = []
  parts << 'AWS4-HMAC-SHA256'
  parts << datetime
  parts << credential_string(datetime)
  parts << EC2::Common::HeadersV4::hexdigest(canonical_request)
  parts.join("\n")
end