From becea65ad84d3a28f99b681fa6cbd1e2153b94fa Mon Sep 17 00:00:00 2001 From: Frederick Cheung Date: Tue, 20 Jan 2015 21:56:37 +0000 Subject: [PATCH] [AWS|Storage] signed_url should use v2 signature when aws_signature_version is 2 --- Gemfile | 1 - lib/fog/aws/storage.rb | 60 ++++++++++++++++++++++++------- tests/models/storage/url_tests.rb | 24 +++++++++++-- 3 files changed, 69 insertions(+), 16 deletions(-) diff --git a/Gemfile b/Gemfile index df52e17f7..2fa492106 100644 --- a/Gemfile +++ b/Gemfile @@ -2,6 +2,5 @@ source 'https://rubygems.org' # Specify your gem's dependencies in fog-aws.gemspec gemspec - gem 'pry-nav', group: :test gem "codeclimate-test-reporter", group: :test, require: nil diff --git a/lib/fog/aws/storage.rb b/lib/fog/aws/storage.rb index 9bcbe8327..e02c4259f 100644 --- a/lib/fog/aws/storage.rb +++ b/lib/fog/aws/storage.rb @@ -141,9 +141,28 @@ module Fog def signed_url(params, expires) #convert expires from a point in time to a delta to now + expires = expires.to_i + if @signature_version == 4 + params = v4_signed_params_for_url(params, expires) + else + params = v2_signed_params_for_url(params, expires) + end + + params_to_url(params) + end + + private + + def validate_signature_version! + unless @signature_version == 2 || @signature_version == 4 + raise "Unknown signature version #{@signature_version}; valid versions are 2 or 4" + end + end + + def v4_signed_params_for_url(params, expires) now = Fog::Time.now - expires = expires.to_i - now.to_i + expires = expires - now.to_i params[:headers] ||= {} params[:query]||= {} @@ -157,14 +176,29 @@ module Fog params = request_params(params) params[:headers][:host] = params[:host] - signature = @signer.signature_parameters(params, now, "UNSIGNED-PAYLOAD") - - params[:query] = (params[:query] || {}).merge(signature) - - params_to_url(params) + signature_query_params = @signer.signature_parameters(params, now, "UNSIGNED-PAYLOAD") + params[:query] = (params[:query] || {}).merge(signature_query_params) + params end - private + def v2_signed_params_for_url(params, expires) + if @aws_session_token + params[:headers]||= {} + params[:headers]['x-amz-security-token'] = @aws_session_token + end + signature = signature_v2(params, expires) + + params = request_params(params) + + signature_query_params = { + 'AWSAccessKeyId' => @aws_access_key_id, + 'Signature' => signature, + 'Expires' => expires, + } + params[:query] = (params[:query] || {}).merge(signature_query_params) + params[:query]['x-amz-security-token'] = @aws_session_token if @aws_session_token + params + end def region_to_host(region=nil) case region.to_s @@ -377,6 +411,8 @@ module Fog @port = options[:port] || DEFAULT_SCHEME_PORT[@scheme] end @path_style = options[:path_style] || false + @signature_version = options.fetch(:aws_signature_version, 4) + validate_signature_version! setup_credentials(options) end @@ -396,6 +432,11 @@ module Fog @signer = Fog::AWS::SignatureV4.new( @aws_access_key_id, @aws_secret_access_key, @region, 's3') end + + def signature_v2(params, expires) + 'foo' + end + end class Real @@ -451,11 +492,6 @@ module Fog private - def validate_signature_version! - unless @signature_version == 2 || @signature_version == 4 - raise "Unknown signature version #{@signature_version}; valid versions are 2 or 4" - end - end def setup_credentials(options) @aws_access_key_id = options[:aws_access_key_id] diff --git a/tests/models/storage/url_tests.rb b/tests/models/storage/url_tests.rb index 48a69e63d..9c5ef29ce 100644 --- a/tests/models/storage/url_tests.rb +++ b/tests/models/storage/url_tests.rb @@ -1,5 +1,4 @@ # encoding: utf-8 - Shindo.tests('AWS | url', ["aws"]) do @@ -14,11 +13,30 @@ Shindo.tests('AWS | url', ["aws"]) do now = Fog::Time.now if RUBY_VERSION > '1.8.7' # ruby 1.8.x doesn't provide hash ordering - tests('#url w/ response-cache-control').returns( + tests('#v4 url w/ response-cache-control').returns( "https://fognonbucket.s3.amazonaws.com/test.txt?response-cache-control=No-cache&X-Amz-Expires=500&X-Amz-Date=#{now.to_iso8601_basic}&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=123/#{now.utc.strftime('%Y%m%d')}/us-east-1/s3/aws4_request&X-Amz-SignedHeaders=host&X-Amz-Signature=" ) do - @file.url(Time.now + 500, :query => { 'response-cache-control' => 'No-cache' }).gsub(/(X-Amz-Signature=)[0-9a-f]+\z/,'\\1') + @file.url(now + 500, :query => { 'response-cache-control' => 'No-cache' }).gsub(/(X-Amz-Signature=)[0-9a-f]+\z/,'\\1') + end + end + + @storage = Fog::Storage.new( + :provider => 'AWS', + :aws_access_key_id => '123', + :aws_secret_access_key => 'abc', + :aws_signature_version => 2, + :region => 'us-east-1' + ) + + @file = @storage.directories.new(:key => 'fognonbucket').files.new(:key => 'test.txt') + + if RUBY_VERSION > '1.8.7' # ruby 1.8.x doesn't provide hash ordering + tests('#v2 url w/ response-cache-control').returns( + "https://fognonbucket.s3.amazonaws.com/test.txt?response-cache-control=No-cache&AWSAccessKeyId=123&Signature=foo&Expires=#{now.to_i + 500}" + ) do + + @file.url(now + 500, :query => { 'response-cache-control' => 'No-cache' }) end end