From eba80bf875639ca682f8babfa878406c02d19f2a Mon Sep 17 00:00:00 2001 From: Sertan GULVEREN Date: Wed, 7 Apr 2021 22:10:15 +0300 Subject: [PATCH 01/16] Default signature version changed Default signature version changed from 2 to 4. Signature version controlling on initialize. --- lib/aws/ses/base.rb | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/lib/aws/ses/base.rb b/lib/aws/ses/base.rb index f5b55a3..186f20d 100644 --- a/lib/aws/ses/base.rb +++ b/lib/aws/ses/base.rb @@ -44,6 +44,8 @@ module SES DEFAULT_MESSAGE_ID_DOMAIN = 'email.amazonses.com' USER_AGENT = 'github-aws-ses-ruby-gem' + + DEFAULT_SIGNATURE_VERSION = 4 # Encodes the given string with the secret_access_key by taking the # hmac-sha1 sum, and then base64 encoding it. Optionally, it will also @@ -107,10 +109,11 @@ def initialize( options = {} ) :path => "/", :user_agent => USER_AGENT, :proxy_server => nil, - :region => DEFAULT_REGION + :region => DEFAULT_REGION, + :signature_version => DEFAULT_SIGNATURE_VERSION }.merge(options) - @signature_version = options[:signature_version] || 2 + @signature_version = options[:signature_version] @server = options[:server] @message_id_domain = options[:message_id_domain] @proxy_server = options[:proxy_server] @@ -125,6 +128,7 @@ def initialize( options = {} ) raise ArgumentError, "No :use_ssl value provided" if options[:use_ssl].nil? raise ArgumentError, "Invalid :use_ssl value provided, only 'true' or 'false' allowed" unless options[:use_ssl] == true || options[:use_ssl] == false raise ArgumentError, "No :server provided" if options[:server].nil? || options[:server].empty? + raise ArgumentError, ":signature_version must be 2 or 4" unless [2, 4].include?(options[:signature_version]) if options[:port] # user-specified port @@ -177,7 +181,7 @@ def request(action, params = {}) req = {} - req['X-Amzn-Authorization'] = get_aws_auth_param(timestamp.httpdate, @secret_access_key, action, signature_version) + req['X-Amzn-Authorization'] = get_aws_auth_param(timestamp.httpdate, @secret_access_key, action) req['Date'] = timestamp.httpdate req['User-Agent'] = @user_agent @@ -194,8 +198,7 @@ def request(action, params = {}) end # Set the Authorization header using AWS signed header authentication - def get_aws_auth_param(timestamp, secret_access_key, action = '', signature_version = 2) - raise(ArgumentError, "signature_version must be `2` or `4`") unless signature_version == 2 || signature_version == 4 + def get_aws_auth_param(timestamp, secret_access_key, action = '') encoded_canonical = SES.encode(secret_access_key, timestamp, false) if signature_version == 4 From 11012374d60371a97771b662ee08e6bb53079e64 Mon Sep 17 00:00:00 2001 From: Sertan GULVEREN Date: Wed, 7 Apr 2021 22:13:04 +0300 Subject: [PATCH 02/16] Base tests revised. Base tests have been revised due to the default signature version change. --- test/base_test.rb | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/test/base_test.rb b/test/base_test.rb index b0c4d6b..6a691ac 100644 --- a/test/base_test.rb +++ b/test/base_test.rb @@ -6,7 +6,7 @@ def test_connection_established assert_not_nil instance.instance_variable_get("@http") end - + def test_failed_response @base = generate_base mock_connection(@base, {:code => 403, :body => %{ @@ -45,10 +45,11 @@ def test_ses_authorization_header_v2 base = ::AWS::SES::Base.new( access_key_id: aws_access_key_id, - secret_access_key: aws_secret_access_key + secret_access_key: aws_secret_access_key, + signature_version: 2 ) - assert_equal 'AWS3-HTTPS AWSAccessKeyId=fake_aws_key_id, Algorithm=HmacSHA256, Signature=eHh/cPIJJUc1+RMCueAi50EPlYxkZNXMrxtGxjkBD1w=', base.get_aws_auth_param(timestamp.httpdate, aws_secret_access_key) + assert_equal 'AWS3-HTTPS AWSAccessKeyId=fake_aws_key_id, Algorithm=HmacSHA256, Signature=eHh/cPIJJUc1+RMCueAi50EPlYxkZNXMrxtGxjkBD1w=', base.get_aws_auth_param(timestamp.httpdate, aws_secret_access_key, '') end def test_ses_authorization_header_v4 @@ -59,12 +60,11 @@ def test_ses_authorization_header_v4 base = ::AWS::SES::Base.new( server: 'ec2.amazonaws.com', - signature_version: 4, access_key_id: aws_access_key_id, secret_access_key: aws_secret_access_key ) - assert_equal 'AWS4-HMAC-SHA256 Credential=fake_aws_key_id/20200702/us-east-1/ec2/aws4_request, SignedHeaders=host;x-amz-date, Signature=c0465b36efd110b14a1c6dcca3e105085ed2bfb2a3fd3b3586cc459326ab43aa', base.get_aws_auth_param(time.httpdate, aws_secret_access_key, 'DescribeRegions', 4) + assert_equal 'AWS4-HMAC-SHA256 Credential=fake_aws_key_id/20200702/us-east-1/ec2/aws4_request, SignedHeaders=host;x-amz-date, Signature=c0465b36efd110b14a1c6dcca3e105085ed2bfb2a3fd3b3586cc459326ab43aa', base.get_aws_auth_param(time.httpdate, aws_secret_access_key, 'DescribeRegions') Timecop.return end @@ -76,12 +76,11 @@ def test_ses_authorization_header_v4_changed_host base = ::AWS::SES::Base.new( server: 'email.us-east-1.amazonaws.com', - signature_version: 4, access_key_id: aws_access_key_id, secret_access_key: aws_secret_access_key ) - assert_equal 'AWS4-HMAC-SHA256 Credential=fake_aws_key_id/20200702/us-east-1/ec2/aws4_request, SignedHeaders=host;x-amz-date, Signature=b872601457070ab98e7038bdcd4dc1f5eab586ececf9908525474408b0740515', base.get_aws_auth_param(time.httpdate, aws_secret_access_key, 'DescribeRegions', 4) + assert_equal 'AWS4-HMAC-SHA256 Credential=fake_aws_key_id/20200702/us-east-1/ec2/aws4_request, SignedHeaders=host;x-amz-date, Signature=b872601457070ab98e7038bdcd4dc1f5eab586ececf9908525474408b0740515', base.get_aws_auth_param(time.httpdate, aws_secret_access_key, 'DescribeRegions') Timecop.return end @@ -93,13 +92,12 @@ def test_ses_authorization_header_v4_changed_region base = ::AWS::SES::Base.new( server: 'email.us-east-1.amazonaws.com', - signature_version: 4, access_key_id: aws_access_key_id, secret_access_key: aws_secret_access_key, region: 'eu-west-1' ) - assert_not_equal 'AWS4-HMAC-SHA256 Credential=fake_aws_key_id/20200702/us-east-1/ec2/aws4_request, SignedHeaders=host;x-amz-date, Signature=b872601457070ab98e7038bdcd4dc1f5eab586ececf9908525474408b0740515', base.get_aws_auth_param(time.httpdate, aws_secret_access_key, 'DescribeRegions', 4) + assert_not_equal 'AWS4-HMAC-SHA256 Credential=fake_aws_key_id/20200702/us-east-1/ec2/aws4_request, SignedHeaders=host;x-amz-date, Signature=b872601457070ab98e7038bdcd4dc1f5eab586ececf9908525474408b0740515', base.get_aws_auth_param(time.httpdate, aws_secret_access_key, 'DescribeRegions') Timecop.return end end From 47d0615730aacfaec3a1b76994677b38b15a2e18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sertan=20G=C3=BClveren?= Date: Wed, 7 Apr 2021 22:29:11 +0300 Subject: [PATCH 03/16] Unnecessary parameter removed --- test/base_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/base_test.rb b/test/base_test.rb index 6a691ac..d258686 100644 --- a/test/base_test.rb +++ b/test/base_test.rb @@ -49,7 +49,7 @@ def test_ses_authorization_header_v2 signature_version: 2 ) - assert_equal 'AWS3-HTTPS AWSAccessKeyId=fake_aws_key_id, Algorithm=HmacSHA256, Signature=eHh/cPIJJUc1+RMCueAi50EPlYxkZNXMrxtGxjkBD1w=', base.get_aws_auth_param(timestamp.httpdate, aws_secret_access_key, '') + assert_equal 'AWS3-HTTPS AWSAccessKeyId=fake_aws_key_id, Algorithm=HmacSHA256, Signature=eHh/cPIJJUc1+RMCueAi50EPlYxkZNXMrxtGxjkBD1w=', base.get_aws_auth_param(timestamp.httpdate, aws_secret_access_key) end def test_ses_authorization_header_v4 From 468cb1b94b2fc68068ee58ff9f060664d6ccf261 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sertan=20G=C3=BClveren?= Date: Thu, 8 Apr 2021 02:11:37 +0300 Subject: [PATCH 04/16] signature v4 changes --- VERSION | 2 +- aws-ses.gemspec | 2 +- lib/aws/ses/base.rb | 100 +++++++++++++++++++++++++------------------- 3 files changed, 58 insertions(+), 46 deletions(-) diff --git a/VERSION b/VERSION index 39e898a..5a848a1 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.7.1 +0.7.1.2 diff --git a/aws-ses.gemspec b/aws-ses.gemspec index d904916..c81a73e 100644 --- a/aws-ses.gemspec +++ b/aws-ses.gemspec @@ -6,7 +6,7 @@ Gem::Specification.new do |s| s.name = "aws-ses".freeze - s.version = "0.7.1" + s.version = "0.7.1.2" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] diff --git a/lib/aws/ses/base.rb b/lib/aws/ses/base.rb index 186f20d..635d0e7 100644 --- a/lib/aws/ses/base.rb +++ b/lib/aws/ses/base.rb @@ -32,21 +32,21 @@ module AWS #:nodoc: # module SES - + API_VERSION = '2010-12-01' DEFAULT_REGION = 'us-east-1' - SERVICE = 'ec2' + SERVICE = 'ses' DEFAULT_HOST = 'email.us-east-1.amazonaws.com' DEFAULT_MESSAGE_ID_DOMAIN = 'email.amazonses.com' - + USER_AGENT = 'github-aws-ses-ruby-gem' DEFAULT_SIGNATURE_VERSION = 4 - + # Encodes the given string with the secret_access_key by taking the # hmac-sha1 sum, and then base64 encoding it. Optionally, it will also # url encode the result of that to protect the string if it's going to @@ -68,9 +68,9 @@ def SES.encode(secret_access_key, str, urlencode=true) return b64_hmac end end - + # Generates the HTTP Header String that Amazon looks for - # + # # @param [String] key the AWS Access Key ID # @param [String] alg the algorithm used for the signature # @param [String] sig the signature itself @@ -83,11 +83,12 @@ def SES.authorization_header_v4(credential, signed_headers, signature) end # AWS::SES::Base is the abstract super class of all classes who make requests against SES - class Base + class Base include SendEmail include Info - - attr_reader :use_ssl, :server, :proxy_server, :port, :message_id_domain, :signature_version, :region + + attr_reader :use_ssl, :server, :proxy_server, :port, :message_id_domain, :signature_version, :region, + :action, :action_time attr_accessor :settings # @option options [String] :access_key_id ("") The user's AWS Access Key ID @@ -111,7 +112,7 @@ def initialize( options = {} ) :proxy_server => nil, :region => DEFAULT_REGION, :signature_version => DEFAULT_SIGNATURE_VERSION - }.merge(options) + }.merge(options) @signature_version = options[:signature_version] @server = options[:server] @@ -154,26 +155,27 @@ def initialize( options = {} ) @http.use_ssl = @use_ssl end - + def connection @http end - - # Make the connection to AWS passing in our request. + + # Make the connection to AWS passing in our request. # allow us to have a one line call in each method which will do all of the work # in making the actual request to AWS. def request(action, params = {}) + @action = action # Use a copy so that we don't modify the caller's Hash, remove any keys that have nil or empty values params = params.reject { |key, value| value.nil? or value.empty?} - - timestamp = Time.now.getutc + + @action_time = Time.now.getutc params.merge!( {"Action" => action, "SignatureVersion" => signature_version.to_s, "SignatureMethod" => 'HmacSHA256', "AWSAccessKeyId" => @access_key_id, "Version" => API_VERSION, - "Timestamp" => timestamp.iso8601 } ) + "Timestamp" => action_time.iso8601 } ) query = params.sort.collect do |param| CGI::escape(param[0]) + "=" + CGI::escape(param[1]) @@ -181,31 +183,42 @@ def request(action, params = {}) req = {} - req['X-Amzn-Authorization'] = get_aws_auth_param(timestamp.httpdate, @secret_access_key, action) - req['Date'] = timestamp.httpdate - req['User-Agent'] = @user_agent - response = connection.post(@path, query, req) - + response = connection.post(@path, query, get_req_headers) + response_class = AWS::SES.const_get( "#{action}Response" ) result = response_class.new(action, response) - + if result.error? raise ResponseError.new(result) end - + result end - # Set the Authorization header using AWS signed header authentication - def get_aws_auth_param(timestamp, secret_access_key, action = '') - encoded_canonical = SES.encode(secret_access_key, timestamp, false) - + def get_req_headers + headers = {} if signature_version == 4 - SES.authorization_header_v4(sig_v4_auth_credential, sig_v4_auth_signed_headers, sig_v4_auth_signature(action)) + headers['host'] = @server + headers['authorization'] = get_aws_auth_header_v4 + headers['x-amz-date'] = amzdate + headers['user-agent'] = @user_agent else - SES.authorization_header(@access_key_id, 'HmacSHA256', encoded_canonical) + headers['x-amzn-authorization'] = get_aws_auth_header_v2 + headers['date'] = action_time.httpdate + headers['user-agent'] = @user_agent end + headers + end + + # Set the Authorization header using AWS signed header authentication + def get_aws_auth_header_v2 + encoded_canonical = SES.encode(@secret_access_key, action_time.httpdate, false) + SES.authorization_header(@access_key_id, 'HmacSHA256', encoded_canonical) + end + + def get_aws_auth_header_v4 + SES.authorization_header_v4(sig_v4_auth_credential, sig_v4_auth_signed_headers, sig_v4_auth_signature) end private @@ -222,24 +235,23 @@ def credential_scope datestamp + '/' + region + '/' + SERVICE + '/' + 'aws4_request' end - def string_to_sign(for_action) - "AWS4-HMAC-SHA256\n" + amzdate + "\n" + credential_scope + "\n" + Digest::SHA256.hexdigest(canonical_request(for_action).encode('utf-8').b) + def string_to_sign + "AWS4-HMAC-SHA256\n" + amzdate + "\n" + credential_scope + "\n" + Digest::SHA256.hexdigest(canonical_request.encode('utf-8').b) end - def amzdate - Time.now.utc.strftime('%Y%m%dT%H%M%SZ') + action_time.strftime('%Y%m%dT%H%M%SZ') end def datestamp - Time.now.utc.strftime('%Y%m%d') + action_time.strftime('%Y%m%d') end - def canonical_request(for_action) - "GET" + "\n" + "/" + "\n" + canonical_querystring(for_action) + "\n" + canonical_headers + "\n" + sig_v4_auth_signed_headers + "\n" + payload_hash + def canonical_request + "POST" + "\n" + "/" + "\n" + canonical_querystring(@action) + "\n" + canonical_headers + "\n" + sig_v4_auth_signed_headers + "\n" + payload_hash end - def canonical_querystring(action) + def canonical_querystring "Action=#{action}&Version=2013-10-15" end @@ -251,16 +263,16 @@ def payload_hash Digest::SHA256.hexdigest(''.encode('utf-8')) end - def sig_v4_auth_signature(for_action) - signing_key = getSignatureKey(@secret_access_key, datestamp, region, SERVICE) + def sig_v4_auth_signature + signing_key = getSignatureKey - OpenSSL::HMAC.hexdigest("SHA256", signing_key, string_to_sign(for_action).encode('utf-8')) + OpenSSL::HMAC.hexdigest("SHA256", signing_key, string_to_sign.encode('utf-8')) end - def getSignatureKey(key, dateStamp, regionName, serviceName) - kDate = sign(('AWS4' + key).encode('utf-8'), dateStamp) - kRegion = sign(kDate, regionName) - kService = sign(kRegion, serviceName) + def getSignatureKey + kDate = sign(('AWS4' + @secret_access_key).encode('utf-8'), datestamp) + kRegion = sign(kDate, region) + kService = sign(kRegion, SERVICE) kSigning = sign(kService, 'aws4_request') kSigning From 87f0f894a264f6319c7a1f373c6a2044dad5b157 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sertan=20G=C3=BClveren?= Date: Thu, 8 Apr 2021 02:14:03 +0300 Subject: [PATCH 05/16] argument errors fixed. --- VERSION | 2 +- aws-ses.gemspec | 2 +- lib/aws/ses/base.rb | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/VERSION b/VERSION index 5a848a1..2eecb29 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.7.1.2 +0.7.1.3 diff --git a/aws-ses.gemspec b/aws-ses.gemspec index c81a73e..d13f6de 100644 --- a/aws-ses.gemspec +++ b/aws-ses.gemspec @@ -6,7 +6,7 @@ Gem::Specification.new do |s| s.name = "aws-ses".freeze - s.version = "0.7.1.2" + s.version = "0.7.1.3" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] diff --git a/lib/aws/ses/base.rb b/lib/aws/ses/base.rb index 635d0e7..4994ab6 100644 --- a/lib/aws/ses/base.rb +++ b/lib/aws/ses/base.rb @@ -166,7 +166,7 @@ def connection def request(action, params = {}) @action = action # Use a copy so that we don't modify the caller's Hash, remove any keys that have nil or empty values - params = params.reject { |key, value| value.nil? or value.empty?} + params = params.reject { |_, value| value.nil? or value.empty?} @action_time = Time.now.getutc @@ -248,7 +248,7 @@ def datestamp end def canonical_request - "POST" + "\n" + "/" + "\n" + canonical_querystring(@action) + "\n" + canonical_headers + "\n" + sig_v4_auth_signed_headers + "\n" + payload_hash + "POST" + "\n" + "/" + "\n" + canonical_querystring + "\n" + canonical_headers + "\n" + sig_v4_auth_signed_headers + "\n" + payload_hash end def canonical_querystring From 036581c66529ebbed0eb4ead3064645b2a0df245 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sertan=20G=C3=BClveren?= Date: Thu, 8 Apr 2021 11:23:43 +0300 Subject: [PATCH 06/16] payload hash fixed --- lib/aws/ses/base.rb | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/lib/aws/ses/base.rb b/lib/aws/ses/base.rb index 4994ab6..6f91881 100644 --- a/lib/aws/ses/base.rb +++ b/lib/aws/ses/base.rb @@ -88,7 +88,7 @@ class Base include Info attr_reader :use_ssl, :server, :proxy_server, :port, :message_id_domain, :signature_version, :region, - :action, :action_time + :action, :action_time, :query attr_accessor :settings # @option options [String] :access_key_id ("") The user's AWS Access Key ID @@ -177,13 +177,9 @@ def request(action, params = {}) "Version" => API_VERSION, "Timestamp" => action_time.iso8601 } ) - query = params.sort.collect do |param| + @query = params.sort.collect do |param| CGI::escape(param[0]) + "=" + CGI::escape(param[1]) end.join("&") - - req = {} - - response = connection.post(@path, query, get_req_headers) response_class = AWS::SES.const_get( "#{action}Response" ) @@ -252,7 +248,7 @@ def canonical_request end def canonical_querystring - "Action=#{action}&Version=2013-10-15" + signature_version == 2 ? "Action=#{action}&Version=2013-10-15" : '' end def canonical_headers @@ -260,7 +256,7 @@ def canonical_headers end def payload_hash - Digest::SHA256.hexdigest(''.encode('utf-8')) + Digest::SHA256.hexdigest(query.encode('utf-8')) end def sig_v4_auth_signature From 146c01fabb7a9c9d97884525c0dd8938f1531bdb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sertan=20G=C3=BClveren?= Date: Thu, 8 Apr 2021 11:24:16 +0300 Subject: [PATCH 07/16] Version updated --- VERSION | 2 +- aws-ses.gemspec | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index 2eecb29..78f3e52 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.7.1.3 +0.7.1.4 diff --git a/aws-ses.gemspec b/aws-ses.gemspec index d13f6de..7af1adf 100644 --- a/aws-ses.gemspec +++ b/aws-ses.gemspec @@ -6,7 +6,7 @@ Gem::Specification.new do |s| s.name = "aws-ses".freeze - s.version = "0.7.1.3" + s.version = "0.7.1.4" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] From 628e9ee0dec340a0ab972015ef75adbb41e041e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sertan=20G=C3=BClveren?= Date: Thu, 8 Apr 2021 11:37:39 +0300 Subject: [PATCH 08/16] Unnecessary variable assignment removed --- lib/aws/ses/base.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/aws/ses/base.rb b/lib/aws/ses/base.rb index 6f91881..0c5c86c 100644 --- a/lib/aws/ses/base.rb +++ b/lib/aws/ses/base.rb @@ -260,9 +260,7 @@ def payload_hash end def sig_v4_auth_signature - signing_key = getSignatureKey - - OpenSSL::HMAC.hexdigest("SHA256", signing_key, string_to_sign.encode('utf-8')) + OpenSSL::HMAC.hexdigest("SHA256", getSignatureKey, string_to_sign.encode('utf-8')) end def getSignatureKey From 26754f76386a8671b9769d461b587542ac84bff3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sertan=20G=C3=BClveren?= Date: Thu, 8 Apr 2021 11:37:48 +0300 Subject: [PATCH 09/16] Version updated --- VERSION | 2 +- aws-ses.gemspec | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index 78f3e52..2fa111b 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.7.1.4 +0.7.1.5 diff --git a/aws-ses.gemspec b/aws-ses.gemspec index 7af1adf..6dc5389 100644 --- a/aws-ses.gemspec +++ b/aws-ses.gemspec @@ -6,7 +6,7 @@ Gem::Specification.new do |s| s.name = "aws-ses".freeze - s.version = "0.7.1.4" + s.version = "0.7.1.5" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] From 831c268c0209c286819bd7b71d0219b1e99c146d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sertan=20G=C3=BClveren?= Date: Thu, 8 Apr 2021 14:08:29 +0300 Subject: [PATCH 10/16] Signature tests revised --- lib/aws/ses/base.rb | 10 ++++++++-- test/base_test.rb | 13 +++++++------ 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/lib/aws/ses/base.rb b/lib/aws/ses/base.rb index 0c5c86c..e773f48 100644 --- a/lib/aws/ses/base.rb +++ b/lib/aws/ses/base.rb @@ -209,7 +209,7 @@ def get_req_headers # Set the Authorization header using AWS signed header authentication def get_aws_auth_header_v2 - encoded_canonical = SES.encode(@secret_access_key, action_time.httpdate, false) + encoded_canonical = SES.encode(@secret_access_key, httpdate, false) SES.authorization_header(@access_key_id, 'HmacSHA256', encoded_canonical) end @@ -236,13 +236,19 @@ def string_to_sign end def amzdate + @action_time ||= Time.now.getutc action_time.strftime('%Y%m%dT%H%M%SZ') end def datestamp + @action_time ||= Time.now.getutc action_time.strftime('%Y%m%d') end + def httpdate + @action_time ||= Time.now.getutc.httpdate + end + def canonical_request "POST" + "\n" + "/" + "\n" + canonical_querystring + "\n" + canonical_headers + "\n" + sig_v4_auth_signed_headers + "\n" + payload_hash end @@ -256,7 +262,7 @@ def canonical_headers end def payload_hash - Digest::SHA256.hexdigest(query.encode('utf-8')) + Digest::SHA256.hexdigest(query.to_s.encode('utf-8')) end def sig_v4_auth_signature diff --git a/test/base_test.rb b/test/base_test.rb index d258686..2a7ceac 100644 --- a/test/base_test.rb +++ b/test/base_test.rb @@ -41,15 +41,16 @@ def test_failed_response def test_ses_authorization_header_v2 aws_access_key_id = 'fake_aws_key_id' aws_secret_access_key = 'fake_aws_access_key' - timestamp = Time.new(2020, 7, 2, 7, 17, 58, '+00:00') - + time = Time.new(2021, 4, 8, 14, 07, 58, '+00:00') + ::Timecop.freeze(time) base = ::AWS::SES::Base.new( access_key_id: aws_access_key_id, secret_access_key: aws_secret_access_key, signature_version: 2 ) - assert_equal 'AWS3-HTTPS AWSAccessKeyId=fake_aws_key_id, Algorithm=HmacSHA256, Signature=eHh/cPIJJUc1+RMCueAi50EPlYxkZNXMrxtGxjkBD1w=', base.get_aws_auth_param(timestamp.httpdate, aws_secret_access_key) + assert_equal 'AWS3-HTTPS AWSAccessKeyId=fake_aws_key_id, Algorithm=HmacSHA256, Signature=Yi984ReKUv7ckcrwvsBgzLlQX/1kyva74+SF+PlrwZ0=', base.get_aws_auth_header_v2 + Timecop.return end def test_ses_authorization_header_v4 @@ -64,7 +65,7 @@ def test_ses_authorization_header_v4 secret_access_key: aws_secret_access_key ) - assert_equal 'AWS4-HMAC-SHA256 Credential=fake_aws_key_id/20200702/us-east-1/ec2/aws4_request, SignedHeaders=host;x-amz-date, Signature=c0465b36efd110b14a1c6dcca3e105085ed2bfb2a3fd3b3586cc459326ab43aa', base.get_aws_auth_param(time.httpdate, aws_secret_access_key, 'DescribeRegions') + assert_equal 'AWS4-HMAC-SHA256 Credential=fake_aws_key_id/20200702/us-east-1/ses/aws4_request, SignedHeaders=host;x-amz-date, Signature=fb25a4a91c6f5c17637c81744998ac664d16ce70982c5ca92c0a62199ef4e7d6', base.get_aws_auth_header_v4 Timecop.return end @@ -80,7 +81,7 @@ def test_ses_authorization_header_v4_changed_host secret_access_key: aws_secret_access_key ) - assert_equal 'AWS4-HMAC-SHA256 Credential=fake_aws_key_id/20200702/us-east-1/ec2/aws4_request, SignedHeaders=host;x-amz-date, Signature=b872601457070ab98e7038bdcd4dc1f5eab586ececf9908525474408b0740515', base.get_aws_auth_param(time.httpdate, aws_secret_access_key, 'DescribeRegions') + assert_equal 'AWS4-HMAC-SHA256 Credential=fake_aws_key_id/20200702/us-east-1/ses/aws4_request, SignedHeaders=host;x-amz-date, Signature=c77a9d002342ac5b210c8f4a054712f9e00335ce9555c359ea8982acfa32db4c', base.get_aws_auth_header_v4 Timecop.return end @@ -97,7 +98,7 @@ def test_ses_authorization_header_v4_changed_region region: 'eu-west-1' ) - assert_not_equal 'AWS4-HMAC-SHA256 Credential=fake_aws_key_id/20200702/us-east-1/ec2/aws4_request, SignedHeaders=host;x-amz-date, Signature=b872601457070ab98e7038bdcd4dc1f5eab586ececf9908525474408b0740515', base.get_aws_auth_param(time.httpdate, aws_secret_access_key, 'DescribeRegions') + assert_not_equal 'AWS4-HMAC-SHA256 Credential=fake_aws_key_id/20200702/us-east-1/ec2/aws4_request, SignedHeaders=host;x-amz-date, Signature=b872601457070ab98e7038bdcd4dc1f5eab586ececf9908525474408b0740515', base.get_aws_auth_header_v4 Timecop.return end end From 4bd67d410fa64b8920fbf37dd55ccb221edb79a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sertan=20G=C3=BClveren?= Date: Thu, 8 Apr 2021 14:09:03 +0300 Subject: [PATCH 11/16] Version updated --- VERSION | 2 +- aws-ses.gemspec | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index 2fa111b..24299ed 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.7.1.5 +0.7.1.6 diff --git a/aws-ses.gemspec b/aws-ses.gemspec index 6dc5389..8e6177e 100644 --- a/aws-ses.gemspec +++ b/aws-ses.gemspec @@ -6,7 +6,7 @@ Gem::Specification.new do |s| s.name = "aws-ses".freeze - s.version = "0.7.1.5" + s.version = "0.7.1.6" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] From 41871d136e41533f021c0b860cb19dc7330fabdb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sertan=20G=C3=BClveren?= Date: Sat, 10 Apr 2021 18:36:59 +0300 Subject: [PATCH 12/16] Version updated. --- README.erb | 4 +++- README.rdoc | 4 +++- VERSION | 2 +- aws-ses.gemspec | 8 ++++---- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/README.erb b/README.erb index 82f0e56..b547bda 100644 --- a/README.erb +++ b/README.erb @@ -1,5 +1,7 @@ = AWS::SES +{http://rubygems.org}[http://badge.fury.io/rb/aws-ses] + <%= docs_for['AWS::SES'] %> == Send E-mail @@ -20,7 +22,7 @@ This gem is compatible with Rails >= 3.0.0 and Ruby 2.3.x To use, first add the gem to your Gemfile: - gem "aws-ses", "~> 0.7.1", :require => 'aws/ses' + gem "aws-ses-sigv4", "~> 0.8.1", :require => 'aws/ses' == For Rails 3.x diff --git a/README.rdoc b/README.rdoc index 05ef4cb..2f292b5 100644 --- a/README.rdoc +++ b/README.rdoc @@ -1,5 +1,7 @@ = AWS::SES +{http://rubygems.org}[http://badge.fury.io/rb/aws-ses] + AWS::SES is a Ruby library for Amazon's Simple Email Service's REST API (http://aws.amazon.com/ses). == Getting started @@ -141,7 +143,7 @@ This gem is compatible with Rails >= 3.0.0 and Ruby 2.3.x To use, first add the gem to your Gemfile: - gem "aws-ses", "~> 0.7.0", :require => 'aws/ses' + gem "aws-ses-sigv4", "~> 0.8.1", :require => 'aws/ses' == For Rails 3.x diff --git a/VERSION b/VERSION index 24299ed..6f4eebd 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.7.1.6 +0.8.1 diff --git a/aws-ses.gemspec b/aws-ses.gemspec index 8e6177e..2c57cf8 100644 --- a/aws-ses.gemspec +++ b/aws-ses.gemspec @@ -5,13 +5,13 @@ # stub: aws-ses 0.7.1 ruby lib Gem::Specification.new do |s| - s.name = "aws-ses".freeze - s.version = "0.7.1.6" + s.name = "aws-ses-sigv4".freeze + s.version = "0.8.1" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["Drew Blas".freeze, "Marcel Molina Jr.".freeze] - s.date = "2020-09-30" + s.date = "2021-04-10" s.description = "Client library for Amazon's Simple Email Service's REST API".freeze s.email = "drew.blas@gmail.com".freeze s.extra_rdoc_files = [ @@ -52,7 +52,7 @@ Gem::Specification.new do |s| "test/response_test.rb", "test/send_email_test.rb" ] - s.homepage = "http://github.com/drewblas/aws-ses".freeze + s.homepage = "http://github.com/sertangulveren/aws-ses".freeze s.licenses = ["MIT".freeze] s.rubygems_version = "2.5.2.3".freeze s.summary = "Client library for Amazon's Simple Email Service's REST API".freeze From 863836d73428deb8e248dc9445488dea5ac404fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sertan=20G=C3=BClveren?= Date: Sat, 10 Apr 2021 18:38:12 +0300 Subject: [PATCH 13/16] Readme updated. --- README.rdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rdoc b/README.rdoc index 2f292b5..ee1e98f 100644 --- a/README.rdoc +++ b/README.rdoc @@ -1,6 +1,6 @@ = AWS::SES -{http://rubygems.org}[http://badge.fury.io/rb/aws-ses] +{http://rubygems.org}[http://badge.fury.io/rb/aws-ses-sigv4] AWS::SES is a Ruby library for Amazon's Simple Email Service's REST API (http://aws.amazon.com/ses). From 1ae4fb83aa937383af69d1912fa92f5052ce9450 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sertan=20G=C3=BClveren?= Date: Sat, 10 Apr 2021 18:45:33 +0300 Subject: [PATCH 14/16] A more appropriate version name --- README.erb | 2 +- README.rdoc | 4 ++-- aws-ses.gemspec | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.erb b/README.erb index b547bda..8dca504 100644 --- a/README.erb +++ b/README.erb @@ -22,7 +22,7 @@ This gem is compatible with Rails >= 3.0.0 and Ruby 2.3.x To use, first add the gem to your Gemfile: - gem "aws-ses-sigv4", "~> 0.8.1", :require => 'aws/ses' + gem "aws-ses-v4", "~> 0.8.1", :require => 'aws/ses' == For Rails 3.x diff --git a/README.rdoc b/README.rdoc index ee1e98f..9c99532 100644 --- a/README.rdoc +++ b/README.rdoc @@ -1,6 +1,6 @@ = AWS::SES -{http://rubygems.org}[http://badge.fury.io/rb/aws-ses-sigv4] +{http://rubygems.org}[http://badge.fury.io/rb/aws-ses-v4] AWS::SES is a Ruby library for Amazon's Simple Email Service's REST API (http://aws.amazon.com/ses). @@ -143,7 +143,7 @@ This gem is compatible with Rails >= 3.0.0 and Ruby 2.3.x To use, first add the gem to your Gemfile: - gem "aws-ses-sigv4", "~> 0.8.1", :require => 'aws/ses' + gem "aws-ses-v4", "~> 0.8.1", :require => 'aws/ses' == For Rails 3.x diff --git a/aws-ses.gemspec b/aws-ses.gemspec index 2c57cf8..0a8612d 100644 --- a/aws-ses.gemspec +++ b/aws-ses.gemspec @@ -5,7 +5,7 @@ # stub: aws-ses 0.7.1 ruby lib Gem::Specification.new do |s| - s.name = "aws-ses-sigv4".freeze + s.name = "aws-ses-v4".freeze s.version = "0.8.1" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= From a7d3c9a2b22ff81996f6e43743939f57f2a5ee3d Mon Sep 17 00:00:00 2001 From: Sertan GULVEREN Date: Sat, 10 Apr 2021 19:27:51 +0300 Subject: [PATCH 15/16] Update CHANGELOG --- CHANGELOG | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index da0735d..d74664c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +0.8.1: +* Bugs fixed for Aws signature V4 version. +* Default AWS signature version has been updated to v4. 0.7.1: * Bugfix in sig version v4 detection From 03970d241be5ac5ae21c13e80057b1c31375f13c Mon Sep 17 00:00:00 2001 From: Sertan GULVEREN Date: Sat, 10 Apr 2021 19:28:10 +0300 Subject: [PATCH 16/16] Update CHANGELOG --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index d74664c..86650f2 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ 0.8.1: * Bugs fixed for Aws signature V4 version. * Default AWS signature version has been updated to v4. + 0.7.1: * Bugfix in sig version v4 detection