aws-sdk-core 2.0.0.rc8 → 2.0.0.rc9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/apis/DynamoDB-2012-08-10.json +1 -0
- data/apis/EC2-2014-05-01.json +15232 -0
- data/apis/ElasticBeanstalk-2010-12-01.json +17 -0
- data/apis/OpsWorks-2013-02-18.json +215 -0
- data/apis/Redshift-2012-12-01.json +72 -0
- data/apis/S3-2006-03-01.json +271 -15
- data/apis/SNS-2010-03-31.json +27 -0
- data/apis/source/ec2-2014-05-01.json +20662 -0
- data/apis/source/ec2-2014-05-01.paginators.json +112 -0
- data/apis/source/ec2-2014-05-01.waiters.json +146 -0
- data/apis/source/elasticbeanstalk-2010-12-01.json +26 -0
- data/apis/source/opsworks-2013-02-18.json +383 -8
- data/apis/source/redshift-2012-12-01.json +187 -60
- data/apis/source/s3-2006-03-01.json +372 -21
- data/apis/source/sns-2010-03-31.json +83 -36
- data/features/s3/objects.feature +10 -0
- data/features/s3/step_definitions.rb +33 -1
- data/features/step_definitions.rb +2 -1
- data/lib/aws.rb +3 -0
- data/lib/aws/api/service_translators/ec2.rb +11 -0
- data/lib/aws/api/service_translators/s3.rb +1 -0
- data/lib/aws/credential_provider_chain.rb +1 -2
- data/lib/aws/error_handler.rb +2 -1
- data/lib/aws/plugins/ec2_copy_encrypted_snapshot.rb +86 -0
- data/lib/aws/plugins/s3_md5s.rb +11 -8
- data/lib/aws/plugins/s3_sse_cpk.rb +42 -0
- data/lib/aws/query/builder.rb +4 -0
- data/lib/aws/query/param.rb +1 -1
- data/lib/aws/signers/base.rb +2 -0
- data/lib/aws/signers/s3.rb +0 -1
- data/lib/aws/signers/v4.rb +73 -22
- data/lib/aws/version.rb +1 -1
- data/spec/aws/operations_spec.rb +19 -15
- data/spec/aws/plugins/s3_md5s_spec.rb +84 -0
- data/spec/aws/query/builder_spec.rb +40 -0
- data/spec/aws/query/param_spec.rb +5 -0
- data/spec/aws/s3_spec.rb +27 -0
- data/spec/aws/signers/v4_spec.rb +1 -1
- data/spec/fixtures/operations/s3/412_response_head.yml +10 -0
- data/spec/spec_helper.rb +7 -0
- data/vendor/seahorse/lib/seahorse/client/handler_list.rb +3 -2
- data/vendor/seahorse/lib/seahorse/client/http/headers.rb +4 -0
- data/vendor/seahorse/lib/seahorse/client/net_http/handler.rb +1 -0
- data/vendor/seahorse/lib/seahorse/client/plugins/operation_methods.rb +4 -2
- data/vendor/seahorse/spec/seahorse/client/handler_list_spec.rb +2 -13
- metadata +15 -2
data/lib/aws/error_handler.rb
CHANGED
@@ -0,0 +1,86 @@
|
|
1
|
+
module Aws
|
2
|
+
module Plugins
|
3
|
+
|
4
|
+
# This plugin auto populates the following request params for the
|
5
|
+
# CopySnapshot API:
|
6
|
+
#
|
7
|
+
# * `:destination_region`
|
8
|
+
# * `:presigned_url`
|
9
|
+
#
|
10
|
+
# These params are required by EC2 when copying an encrypted snapshot.
|
11
|
+
class EC2CopyEncryptedSnapshot < Seahorse::Client::Plugin
|
12
|
+
|
13
|
+
# @api private
|
14
|
+
class Handler < Seahorse::Client::Handler
|
15
|
+
|
16
|
+
def call(context)
|
17
|
+
params = context.params
|
18
|
+
unless params.key?(:destination_region)
|
19
|
+
params[:destination_region] = context.config.region
|
20
|
+
params[:presigned_url] = presigned_url(context.client, params)
|
21
|
+
end
|
22
|
+
@handler.call(context)
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def presigned_url(client, params)
|
28
|
+
client = source_region_client(client, params)
|
29
|
+
client.handle(PresignHandler, step: :build, priority: 0)
|
30
|
+
client.copy_snapshot(params).data # presigned url
|
31
|
+
end
|
32
|
+
|
33
|
+
def source_region_client(client, params)
|
34
|
+
config = client.config.to_h
|
35
|
+
config.delete(:endpoint)
|
36
|
+
config[:region] = params[:source_region]
|
37
|
+
client.class.new(config)
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
# This handler intentionally does NOT call the next handler in
|
43
|
+
# the stack. It generates a presigned url from the request
|
44
|
+
# and returns it as the response data.
|
45
|
+
#
|
46
|
+
# Before signing:
|
47
|
+
#
|
48
|
+
# * The HTTP method is changed from POST to GET
|
49
|
+
# * The url-encoded body is moved to the querystring
|
50
|
+
#
|
51
|
+
# @api private
|
52
|
+
class PresignHandler < Seahorse::Client::Handler
|
53
|
+
|
54
|
+
def call(context)
|
55
|
+
convert_post_2_get(context)
|
56
|
+
Seahorse::Client::Response.new(
|
57
|
+
context: context,
|
58
|
+
data: presigned_url(context.http_request, context.config))
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
def convert_post_2_get(context)
|
64
|
+
context.http_request.http_method = 'GET'
|
65
|
+
context.http_request.endpoint = new_endpoint(context)
|
66
|
+
context.http_request.body = ''
|
67
|
+
end
|
68
|
+
|
69
|
+
def new_endpoint(context)
|
70
|
+
body = context.http_request.body_contents
|
71
|
+
endpoint = context.http_request.endpoint.to_s + '?' + body
|
72
|
+
Seahorse::Client::Http::Endpoint.new(endpoint)
|
73
|
+
end
|
74
|
+
|
75
|
+
def presigned_url(http_request, config)
|
76
|
+
signer = Signers::V4.new('ec2', config.credentials, config.region)
|
77
|
+
signer.presigned_url(http_request, expires_in: 3600)
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
handler(Handler, step: :initialize, operations: [:copy_snapshot])
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
data/lib/aws/plugins/s3_md5s.rb
CHANGED
@@ -1,13 +1,14 @@
|
|
1
|
-
require '
|
1
|
+
require 'openssl'
|
2
2
|
require 'base64'
|
3
3
|
|
4
4
|
module Aws
|
5
5
|
module Plugins
|
6
6
|
|
7
7
|
# @seahorse.client.option [Boolean] :compute_checksums (true)
|
8
|
-
# When `true` a MD5 checksum will be computed for
|
9
|
-
#
|
10
|
-
#
|
8
|
+
# When `true` a MD5 checksum will be computed for every request that
|
9
|
+
# sends a body. When `false`, MD5 checksums will only be computed
|
10
|
+
# for operations that require them. Checksum errors returned by Amazon
|
11
|
+
# S3 are automatically retried up to `:retry_limit` times.
|
11
12
|
class S3Md5s < Seahorse::Client::Plugin
|
12
13
|
|
13
14
|
# Amazon S3 requires these operations to have an MD5 checksum
|
@@ -25,13 +26,15 @@ module Aws
|
|
25
26
|
OneMB = 1024 * 1024
|
26
27
|
|
27
28
|
def call(context)
|
28
|
-
context.http_request.
|
29
|
+
body = context.http_request.body
|
30
|
+
if body.size > 0
|
31
|
+
context.http_request.headers['Content-Md5'] ||= md5(body)
|
32
|
+
end
|
29
33
|
@handler.call(context)
|
30
34
|
end
|
31
35
|
|
32
|
-
def md5(
|
33
|
-
md5 = Digest::MD5.new
|
34
|
-
body = context.http_request.body
|
36
|
+
def md5(body)
|
37
|
+
md5 = OpenSSL::Digest::MD5.new
|
35
38
|
while chunk = body.read(OneMB)
|
36
39
|
md5.update(chunk)
|
37
40
|
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'openssl'
|
2
|
+
require 'base64'
|
3
|
+
|
4
|
+
module Aws
|
5
|
+
module Plugins
|
6
|
+
class S3SseCpk < Seahorse::Client::Plugin
|
7
|
+
|
8
|
+
class Handler < Seahorse::Client::Handler
|
9
|
+
|
10
|
+
def call(context)
|
11
|
+
compute_key_md5(context.params)
|
12
|
+
@handler.call(context)
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def compute_key_md5(params)
|
18
|
+
if key = params[:sse_customer_key]
|
19
|
+
params[:sse_customer_key] = base64(key)
|
20
|
+
params[:sse_customer_key_md5] = base64(md5(key))
|
21
|
+
end
|
22
|
+
if key = params[:copy_source_sse_customer_key]
|
23
|
+
params[:copy_source_sse_customer_key] = base64(key)
|
24
|
+
params[:copy_source_sse_customer_key_md5] = base64(md5(key))
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def md5(str)
|
29
|
+
OpenSSL::Digest::MD5.digest(str)
|
30
|
+
end
|
31
|
+
|
32
|
+
def base64(str)
|
33
|
+
Base64.encode64(str).strip
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
handler(Handler, step: :initialize)
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/lib/aws/query/builder.rb
CHANGED
data/lib/aws/query/param.rb
CHANGED
data/lib/aws/signers/base.rb
CHANGED
data/lib/aws/signers/s3.rb
CHANGED
data/lib/aws/signers/v4.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'time'
|
2
|
-
require 'digest/sha1'
|
3
2
|
require 'openssl'
|
4
3
|
|
5
4
|
module Aws
|
@@ -8,8 +7,8 @@ module Aws
|
|
8
7
|
|
9
8
|
def self.sign(context)
|
10
9
|
new(
|
11
|
-
context.config.credentials,
|
12
10
|
context.config.sigv4_name,
|
11
|
+
context.config.credentials,
|
13
12
|
context.config.sigv4_region
|
14
13
|
).sign(context.http_request)
|
15
14
|
end
|
@@ -20,48 +19,94 @@ module Aws
|
|
20
19
|
# the endpoint prefix.
|
21
20
|
# @param [String] region The region (e.g. 'us-west-1') the request
|
22
21
|
# will be made to.
|
23
|
-
def initialize(
|
24
|
-
@credentials = credentials
|
22
|
+
def initialize(service_name, credentials, region)
|
25
23
|
@service_name = service_name
|
24
|
+
@credentials = credentials
|
26
25
|
@region = region
|
27
26
|
end
|
28
27
|
|
29
28
|
# @param [Seahorse::Client::Http::Request] request
|
30
29
|
# @return [Seahorse::Client::Http::Request] the signed request.
|
31
|
-
def sign(
|
30
|
+
def sign(req)
|
32
31
|
datetime = Time.now.utc.strftime("%Y%m%dT%H%M%SZ")
|
33
|
-
|
34
|
-
|
35
|
-
|
32
|
+
body_digest = req.headers['X-Amz-Content-Sha256'] || hexdigest(req.body)
|
33
|
+
req.headers['X-Amz-Date'] = datetime
|
34
|
+
req.headers['Host'] = req.endpoint.host
|
35
|
+
req.headers['X-Amz-Security-Token'] = credentials.session_token if
|
36
36
|
credentials.session_token
|
37
|
-
|
38
|
-
|
39
|
-
|
37
|
+
req.headers['X-Amz-Content-Sha256'] ||= body_digest
|
38
|
+
req.headers['Authorization'] = authorization(req, datetime, body_digest)
|
39
|
+
req
|
40
40
|
end
|
41
41
|
|
42
|
-
|
42
|
+
# Generates an returns a presigned URL.
|
43
|
+
# @param [Seahorse::Client::Http::Request] request
|
44
|
+
# @option options [required, Integer<Seconds>] :expires_in
|
45
|
+
# @option options [optional, String] :body_digest The SHA256 hexdigest of
|
46
|
+
# the payload to sign. For S3, this should be the string literal
|
47
|
+
# `UNSIGNED-PALOAD`.
|
48
|
+
# @return [Seahorse::Client::Http::Request] the signed request.
|
49
|
+
# @api private
|
50
|
+
def presigned_url(request, options = {})
|
51
|
+
now = Time.now.utc.strftime("%Y%m%dT%H%M%SZ")
|
52
|
+
body_digest = options[:body_digest] || hexdigest(request.body)
|
53
|
+
|
54
|
+
params = Query::ParamList.new
|
55
|
+
|
56
|
+
request.headers['Host'] ||= request.endpoint.host
|
57
|
+
request.headers.each do |header_name, header_value|
|
58
|
+
if header_name.match(/^x-amz/)
|
59
|
+
params.set(header_name, header_value)
|
60
|
+
end
|
61
|
+
unless %w(host content-md5).include?(header_name)
|
62
|
+
request.headers.delete(header_name)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
params.set("X-Amz-Algorithm", "AWS4-HMAC-SHA256")
|
67
|
+
params.set("X-Amz-Date", now)
|
68
|
+
params.set("X-Amz-SignedHeaders", signed_headers(request))
|
69
|
+
params.set("X-Amz-Expires", options[:expires_in].to_s)
|
70
|
+
params.set('X-Amz-Security-Token', credentials.session_token) if
|
71
|
+
credentials.session_token
|
72
|
+
params.set("X-Amz-Credential", credential(now))
|
73
|
+
|
74
|
+
endpoint = request.endpoint
|
75
|
+
if endpoint.querystring
|
76
|
+
endpoint.request_uri += '&' + params.to_s
|
77
|
+
else
|
78
|
+
endpoint.request_uri += '?' + params.to_s
|
79
|
+
end
|
80
|
+
endpoint.to_s + '&X-Amz-Signature=' + signature(request, now, body_digest)
|
81
|
+
end
|
82
|
+
|
83
|
+
def authorization(request, datetime, body_digest)
|
43
84
|
parts = []
|
44
|
-
parts << "AWS4-HMAC-SHA256 Credential=#{
|
85
|
+
parts << "AWS4-HMAC-SHA256 Credential=#{credential(datetime)}"
|
45
86
|
parts << "SignedHeaders=#{signed_headers(request)}"
|
46
|
-
parts << "Signature=#{signature(request, datetime)}"
|
87
|
+
parts << "Signature=#{signature(request, datetime, body_digest)}"
|
47
88
|
parts.join(', ')
|
48
89
|
end
|
49
90
|
|
50
|
-
def
|
91
|
+
def credential(datetime)
|
92
|
+
"#{credentials.access_key_id}/#{credential_scope(datetime)}"
|
93
|
+
end
|
94
|
+
|
95
|
+
def signature(request, datetime, body_digest)
|
51
96
|
k_secret = credentials.secret_access_key
|
52
97
|
k_date = hmac("AWS4" + k_secret, datetime[0,8])
|
53
98
|
k_region = hmac(k_date, region)
|
54
99
|
k_service = hmac(k_region, service_name)
|
55
100
|
k_credentials = hmac(k_service, 'aws4_request')
|
56
|
-
hexhmac(k_credentials, string_to_sign(request, datetime))
|
101
|
+
hexhmac(k_credentials, string_to_sign(request, datetime, body_digest))
|
57
102
|
end
|
58
103
|
|
59
|
-
def string_to_sign(request, datetime)
|
104
|
+
def string_to_sign(request, datetime, body_digest)
|
60
105
|
parts = []
|
61
106
|
parts << 'AWS4-HMAC-SHA256'
|
62
107
|
parts << datetime
|
63
108
|
parts << credential_scope(datetime)
|
64
|
-
parts << hexdigest(canonical_request(request))
|
109
|
+
parts << hexdigest(canonical_request(request, body_digest))
|
65
110
|
parts.join("\n")
|
66
111
|
end
|
67
112
|
|
@@ -74,17 +119,23 @@ module Aws
|
|
74
119
|
parts.join("/")
|
75
120
|
end
|
76
121
|
|
77
|
-
def canonical_request(request)
|
122
|
+
def canonical_request(request, body_digest)
|
78
123
|
[
|
79
124
|
request.http_method,
|
80
125
|
request.endpoint.path,
|
81
|
-
request.endpoint.querystring,
|
126
|
+
normalized_querystring(request.endpoint.querystring),
|
82
127
|
canonical_headers(request) + "\n",
|
83
128
|
signed_headers(request),
|
84
|
-
|
129
|
+
body_digest
|
85
130
|
].join("\n")
|
86
131
|
end
|
87
132
|
|
133
|
+
def normalized_querystring(querystring)
|
134
|
+
if querystring
|
135
|
+
querystring.split('&').sort.join('&')
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
88
139
|
def signed_headers(request)
|
89
140
|
headers = request.headers.keys
|
90
141
|
headers.delete('authorization')
|
@@ -106,7 +157,7 @@ module Aws
|
|
106
157
|
end
|
107
158
|
|
108
159
|
def hexdigest(value)
|
109
|
-
digest = Digest::SHA256.new
|
160
|
+
digest = OpenSSL::Digest::SHA256.new
|
110
161
|
if value.respond_to?(:read)
|
111
162
|
chunk = nil
|
112
163
|
chunk_size = 1024 * 1024 # 1 megabyte
|
data/lib/aws/version.rb
CHANGED
data/spec/aws/operations_spec.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
+
require 'stringio'
|
2
3
|
|
3
4
|
module Aws
|
4
5
|
describe 'Aws' do
|
@@ -116,27 +117,30 @@ module Aws
|
|
116
117
|
fixture_name = path.split('/')[-1][0..-5]
|
117
118
|
|
118
119
|
it(fixture_name) do
|
119
|
-
|
120
|
-
|
120
|
+
begin
|
121
|
+
# load the fixture from disk
|
122
|
+
f = OperationFixture.load(svc_name, fixture_name)
|
121
123
|
|
122
|
-
|
123
|
-
|
124
|
-
|
124
|
+
# remove the plugin that raises errors
|
125
|
+
Aws.service_classes[svc_name.to_sym].remove_plugin(
|
126
|
+
Seahorse::Client::Plugins::RaiseResponseErrors)
|
125
127
|
|
126
|
-
|
127
|
-
|
128
|
+
# build the service interface
|
129
|
+
svc = Aws.send(svc_name, f.config)
|
128
130
|
|
129
|
-
|
130
|
-
|
131
|
-
|
131
|
+
# build the request
|
132
|
+
req = svc.build_request(f.operation, f.params)
|
133
|
+
req.handler(f.handler, step: :send)
|
132
134
|
|
133
135
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
request_assertions(f, resp.context.http_request)
|
138
|
-
response_assertions(f, resp)
|
136
|
+
# send the request
|
137
|
+
resp = req.send_request
|
139
138
|
|
139
|
+
request_assertions(f, resp.context.http_request)
|
140
|
+
response_assertions(f, resp)
|
141
|
+
ensure
|
142
|
+
Aws.service_classes[svc_name.to_sym].add_plugin(Seahorse::Client::Plugins::RaiseResponseErrors)
|
143
|
+
end
|
140
144
|
end
|
141
145
|
end
|
142
146
|
end
|