summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/rubygems/remote_fetcher.rb96
-rw-r--r--test/rubygems/test_gem_remote_fetcher.rb138
2 files changed, 207 insertions, 27 deletions
@@ -343,31 +343,71 @@ class Gem::RemoteFetcher
protected
# we have our own signing code here to avoid a dependency on the aws-sdk gem
# fortunately, a simple GET request isn't too complex to sign properly
def sign_s3_url(uri, expiration = nil)
require 'base64'
require 'openssl'
- id, secret = s3_source_auth uri
-
- expiration ||= s3_expiration
- canonical_path = "/#{uri.host}#{uri.path}"
- payload = "GET\n\n\n#{expiration}\n#{canonical_path}"
- digest = OpenSSL::HMAC.digest('sha1', secret, payload)
- # URI.escape is deprecated, and there isn't yet a replacement that does quite what we want
- signature = Base64.encode64(digest).gsub("\n", '').gsub(/[\+\/=]/) { |c| BASE64_URI_TRANSLATE[c] }
- URI.parse("https://#{uri.host}.s3.amazonaws.com#{uri.path}?AWSAccessKeyId=#{id}&Expires=#{expiration}&Signature=#{signature}")
- end
-
- def s3_expiration
- (Time.now + 3600).to_i # one hour from now
end
BASE64_URI_TRANSLATE = { '+' => '%2B', '/' => '%2F', '=' => '%3D' }.freeze
private
def proxy_for(proxy, uri)
Gem::Request.proxy_uri(proxy || Gem::Request.get_proxy_from_env(uri.scheme))
end
@@ -379,7 +419,7 @@ class Gem::RemoteFetcher
end
def s3_source_auth(uri)
- return [uri.user, uri.password] if uri.user && uri.password
s3_source = Gem.configuration[:s3_source] || Gem.configuration['s3_source']
host = uri.host
@@ -388,11 +428,31 @@ class Gem::RemoteFetcher
auth = s3_source[host] || s3_source[host.to_sym]
raise FetchError.new("no key for host #{host} in s3_source in .gemrc", "s3://#{host}") unless auth
- id = auth[:id] || auth['id']
- secret = auth[:secret] || auth['secret']
- raise FetchError.new("s3_source for #{host} missing id or secret", "s3://#{host}") unless id and secret
- [id, secret]
end
end
@@ -650,25 +650,27 @@ PeIQQkFng2VVot/WAQbv3ePqWq07g1BBcwIBAg==
assert_equal "murphy", fetcher.fetch_path(@server_uri)
end
- def assert_fetch_s3(url)
fetcher = Gem::RemoteFetcher.new nil
@fetcher = fetcher
$fetched_uri = nil
def fetcher.request(uri, request_class, last_modified = nil)
$fetched_uri = uri
res = Net::HTTPOK.new nil, 200, nil
- def res.body() 'success' end
res
end
- def fetcher.s3_expiration
- 1395098371
- end
-
data = fetcher.fetch_s3 URI.parse(url)
- assert_equal 'https://my-bucket.s3.amazonaws.com/gems/specs.4.8.gz?AWSAccessKeyId=testuser&Expires=1395098371&Signature=eUTr7NkpZEet%2BJySE%2BfH6qukroI%3D', $fetched_uri.to_s
assert_equal 'success', data
ensure
$fetched_uri = nil
@@ -679,14 +681,132 @@ PeIQQkFng2VVot/WAQbv3ePqWq07g1BBcwIBAg==
'my-bucket' => {:id => 'testuser', :secret => 'testpass'}
}
url = 's3://my-bucket/gems/specs.4.8.gz'
- assert_fetch_s3 url
ensure
Gem.configuration[:s3_source] = nil
end
def test_fetch_s3_url_creds
url = 's3://testuser:testpass@my-bucket/gems/specs.4.8.gz'
- assert_fetch_s3 url
end
def refute_fetch_s3(url, expected_message)