aws-sdk-core 2.0.0.rc8 → 2.0.0.rc9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|