1
0
Fork 0
mirror of https://github.com/fog/fog.git synced 2022-11-09 13:51:43 -05:00

[AWS] Implement signature v4

This commit is contained in:
Frederick Cheung 2012-09-01 16:42:02 +01:00
parent 93812c2ffe
commit e008b358dc
4 changed files with 110 additions and 0 deletions

View file

@ -1,5 +1,6 @@
require 'fog/core'
require 'fog/aws/credential_fetcher'
require 'fog/aws/signaturev4'
module Fog
module AWS

View file

@ -0,0 +1,73 @@
# See http://docs.amazonwebservices.com/general/latest/gr/signature-version-4.html
#
module Fog
module AWS
class SignatureV4
def initialize(aws_access_key_id, secret_key, region,service)
@region = region
@service = service
@aws_access_key_id = aws_access_key_id
@hmac = Fog::HMAC.new('sha256', 'AWS4' + secret_key)
end
def sign(params, date)
canonical_request = <<-DATA
#{params[:method].to_s.upcase}
#{params[:path]}
#{canonical_query_string(params[:query])}
#{canonical_headers(params[:headers])}
#{signed_headers(params[:headers])}
#{Digest::SHA256.hexdigest(params[:body] || '')}
DATA
canonical_request.chop!
credential_scope = "#{date.utc.strftime('%Y%m%d')}/#{@region}/#{@service}/aws4_request"
string_to_sign = <<-DATA
AWS4-HMAC-SHA256
#{date.to_iso8601_basic}
#{credential_scope}
#{Digest::SHA256.hexdigest(canonical_request)}
DATA
string_to_sign.chop!
signature = derived_hmac(date).sign(string_to_sign)
"AWS4-HMAC-SHA256 Credential=#{@aws_access_key_id}/#{credential_scope}, SignedHeaders=#{signed_headers(params[:headers])}, Signature=#{signature.unpack('H*').first}"
end
protected
def canonical_query_string(query)
canonical_query_string = []
for key in (query || {}).keys.sort
component = "#{Fog::AWS.escape(key)}=#{Fog::AWS.escape(query[key].to_s)}"
canonical_query_string << component
end
canonical_query_string.join("&")
end
def canonical_headers(headers)
canonical_headers = ''
for key in headers.keys.sort
canonical_headers << "#{key.downcase}:#{headers[key].to_s.strip}\n"
end
canonical_headers
end
def signed_headers(headers)
headers.keys.sort.collect {|key| key.downcase}.join(';')
end
def derived_hmac(date)
kDate = @hmac.sign(date.utc.strftime('%Y%m%d'))
kRegion = Fog::HMAC.new('sha256', kDate).sign(@region)
kService = Fog::HMAC.new('sha256', kRegion).sign(@service)
kSigning = Fog::HMAC.new('sha256', kService).sign('aws4_request')
Fog::HMAC.new('sha256', kSigning)
end
end
end
end

View file

@ -22,5 +22,9 @@ module Fog
self.utc.strftime("#{DAYS[self.utc.wday]}, %d #{MONTHS[self.utc.month - 1]} %Y %H:%M:%S +0000")
end
def to_iso8601_basic
self.utc.strftime('%Y%m%dT%H%M%SZ')
end
end
end

View file

@ -0,0 +1,32 @@
# encoding: utf-8
Shindo.tests('AWS | signaturev4', ['aws']) do
# These testcases are from http://docs.amazonwebservices.com/general/latest/gr/signature-v4-test-suite.html
@signer = Fog::AWS::SignatureV4.new('AKIDEXAMPLE', 'wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY', 'us-east-1','host')
Fog::Time.now = ::Time.utc(2011,9,9,23,36,0)
#get-vanilla
returns(@signer.sign({:headers => {'Host' => 'host.foo.com', 'Date' => 'Mon, 09 Sep 2011 23:36:00 GMT'}, :method => :get, :path => '/'}, Fog::Time.now)) do
'AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470'
end
#get-vanilla-query-order-key
returns(@signer.sign({:query => {'a' => 'foo', 'b' => 'foo'}, :headers => {'Host' => 'host.foo.com', 'Date' => 'Mon, 09 Sep 2011 23:36:00 GMT'}, :method => :get, :path => '/'}, Fog::Time.now)) do
'AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=0dc122f3b28b831ab48ba65cb47300de53fbe91b577fe113edac383730254a3b'
end
#get-unreserved
returns(@signer.sign({:headers => {'Host' => 'host.foo.com', 'Date' => 'Mon, 09 Sep 2011 23:36:00 GMT'}, :method => :get, :path => '/-._~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'}, Fog::Time.now)) do
'AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=830cc36d03f0f84e6ee4953fbe701c1c8b71a0372c63af9255aa364dd183281e'
end
#post-x-www-form-urlencoded-parameter
returns(@signer.sign({:headers => {'Content-type' => 'application/x-www-form-urlencoded; charset=utf8', 'Host' => 'host.foo.com', 'Date' => 'Mon, 09 Sep 2011 23:36:00 GMT'}, :method => :post, :path => '/',
:body => 'foo=bar'}, Fog::Time.now)) do
'AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=content-type;date;host, Signature=b105eb10c6d318d2294de9d49dd8b031b55e3c3fe139f2e637da70511e9e7b71'
end
Fog::Time.now = ::Time.now
end