mss-sdk 1.0.0

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.
Files changed (131) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +9 -0
  3. data/LICENSE.txt +0 -0
  4. data/README.md +192 -0
  5. data/bin/mss-rb +178 -0
  6. data/ca-bundle.crt +3554 -0
  7. data/lib/mss/core/async_handle.rb +89 -0
  8. data/lib/mss/core/cacheable.rb +76 -0
  9. data/lib/mss/core/client.rb +786 -0
  10. data/lib/mss/core/collection/simple.rb +81 -0
  11. data/lib/mss/core/collection/with_limit_and_next_token.rb +70 -0
  12. data/lib/mss/core/collection/with_next_token.rb +96 -0
  13. data/lib/mss/core/collection.rb +262 -0
  14. data/lib/mss/core/configuration.rb +527 -0
  15. data/lib/mss/core/credential_providers.rb +653 -0
  16. data/lib/mss/core/data.rb +251 -0
  17. data/lib/mss/core/deprecations.rb +83 -0
  18. data/lib/mss/core/endpoints.rb +36 -0
  19. data/lib/mss/core/http/connection_pool.rb +374 -0
  20. data/lib/mss/core/http/curb_handler.rb +150 -0
  21. data/lib/mss/core/http/handler.rb +88 -0
  22. data/lib/mss/core/http/net_http_handler.rb +144 -0
  23. data/lib/mss/core/http/patch.rb +98 -0
  24. data/lib/mss/core/http/request.rb +258 -0
  25. data/lib/mss/core/http/response.rb +80 -0
  26. data/lib/mss/core/indifferent_hash.rb +87 -0
  27. data/lib/mss/core/inflection.rb +55 -0
  28. data/lib/mss/core/ini_parser.rb +41 -0
  29. data/lib/mss/core/json_client.rb +46 -0
  30. data/lib/mss/core/json_parser.rb +75 -0
  31. data/lib/mss/core/json_request_builder.rb +34 -0
  32. data/lib/mss/core/json_response_parser.rb +78 -0
  33. data/lib/mss/core/lazy_error_classes.rb +107 -0
  34. data/lib/mss/core/log_formatter.rb +426 -0
  35. data/lib/mss/core/managed_file.rb +31 -0
  36. data/lib/mss/core/meta_utils.rb +44 -0
  37. data/lib/mss/core/model.rb +61 -0
  38. data/lib/mss/core/naming.rb +29 -0
  39. data/lib/mss/core/option_grammar.rb +737 -0
  40. data/lib/mss/core/options/json_serializer.rb +81 -0
  41. data/lib/mss/core/options/validator.rb +154 -0
  42. data/lib/mss/core/options/xml_serializer.rb +117 -0
  43. data/lib/mss/core/page_result.rb +74 -0
  44. data/lib/mss/core/policy.rb +938 -0
  45. data/lib/mss/core/query_client.rb +40 -0
  46. data/lib/mss/core/query_error_parser.rb +23 -0
  47. data/lib/mss/core/query_request_builder.rb +46 -0
  48. data/lib/mss/core/query_response_parser.rb +34 -0
  49. data/lib/mss/core/region.rb +84 -0
  50. data/lib/mss/core/region_collection.rb +79 -0
  51. data/lib/mss/core/resource.rb +412 -0
  52. data/lib/mss/core/resource_cache.rb +39 -0
  53. data/lib/mss/core/response.rb +214 -0
  54. data/lib/mss/core/response_cache.rb +49 -0
  55. data/lib/mss/core/rest_error_parser.rb +23 -0
  56. data/lib/mss/core/rest_json_client.rb +39 -0
  57. data/lib/mss/core/rest_request_builder.rb +153 -0
  58. data/lib/mss/core/rest_response_parser.rb +65 -0
  59. data/lib/mss/core/rest_xml_client.rb +46 -0
  60. data/lib/mss/core/service_interface.rb +82 -0
  61. data/lib/mss/core/signers/base.rb +45 -0
  62. data/lib/mss/core/signers/cloud_front.rb +55 -0
  63. data/lib/mss/core/signers/s3.rb +158 -0
  64. data/lib/mss/core/signers/version_2.rb +71 -0
  65. data/lib/mss/core/signers/version_3.rb +85 -0
  66. data/lib/mss/core/signers/version_3_https.rb +60 -0
  67. data/lib/mss/core/signers/version_4/chunk_signed_stream.rb +190 -0
  68. data/lib/mss/core/signers/version_4.rb +227 -0
  69. data/lib/mss/core/uri_escape.rb +43 -0
  70. data/lib/mss/core/xml/frame.rb +245 -0
  71. data/lib/mss/core/xml/frame_stack.rb +84 -0
  72. data/lib/mss/core/xml/grammar.rb +306 -0
  73. data/lib/mss/core/xml/parser.rb +69 -0
  74. data/lib/mss/core/xml/root_frame.rb +64 -0
  75. data/lib/mss/core/xml/sax_handlers/libxml.rb +46 -0
  76. data/lib/mss/core/xml/sax_handlers/nokogiri.rb +55 -0
  77. data/lib/mss/core/xml/sax_handlers/ox.rb +40 -0
  78. data/lib/mss/core/xml/sax_handlers/rexml.rb +46 -0
  79. data/lib/mss/core/xml/stub.rb +122 -0
  80. data/lib/mss/core.rb +602 -0
  81. data/lib/mss/errors.rb +161 -0
  82. data/lib/mss/rails.rb +194 -0
  83. data/lib/mss/s3/access_control_list.rb +262 -0
  84. data/lib/mss/s3/acl_object.rb +263 -0
  85. data/lib/mss/s3/acl_options.rb +200 -0
  86. data/lib/mss/s3/bucket.rb +757 -0
  87. data/lib/mss/s3/bucket_collection.rb +161 -0
  88. data/lib/mss/s3/bucket_lifecycle_configuration.rb +472 -0
  89. data/lib/mss/s3/bucket_region_cache.rb +51 -0
  90. data/lib/mss/s3/bucket_tag_collection.rb +110 -0
  91. data/lib/mss/s3/bucket_version_collection.rb +78 -0
  92. data/lib/mss/s3/cipher_io.rb +119 -0
  93. data/lib/mss/s3/client/xml.rb +265 -0
  94. data/lib/mss/s3/client.rb +2076 -0
  95. data/lib/mss/s3/config.rb +60 -0
  96. data/lib/mss/s3/cors_rule.rb +107 -0
  97. data/lib/mss/s3/cors_rule_collection.rb +193 -0
  98. data/lib/mss/s3/data_options.rb +190 -0
  99. data/lib/mss/s3/encryption_utils.rb +145 -0
  100. data/lib/mss/s3/errors.rb +93 -0
  101. data/lib/mss/s3/multipart_upload.rb +353 -0
  102. data/lib/mss/s3/multipart_upload_collection.rb +75 -0
  103. data/lib/mss/s3/object_collection.rb +355 -0
  104. data/lib/mss/s3/object_metadata.rb +102 -0
  105. data/lib/mss/s3/object_upload_collection.rb +76 -0
  106. data/lib/mss/s3/object_version.rb +153 -0
  107. data/lib/mss/s3/object_version_collection.rb +88 -0
  108. data/lib/mss/s3/paginated_collection.rb +74 -0
  109. data/lib/mss/s3/policy.rb +73 -0
  110. data/lib/mss/s3/prefix_and_delimiter_collection.rb +46 -0
  111. data/lib/mss/s3/prefixed_collection.rb +84 -0
  112. data/lib/mss/s3/presign_v4.rb +135 -0
  113. data/lib/mss/s3/presigned_post.rb +574 -0
  114. data/lib/mss/s3/region_detection.rb +75 -0
  115. data/lib/mss/s3/request.rb +61 -0
  116. data/lib/mss/s3/s3_object.rb +1795 -0
  117. data/lib/mss/s3/tree/branch_node.rb +67 -0
  118. data/lib/mss/s3/tree/child_collection.rb +103 -0
  119. data/lib/mss/s3/tree/leaf_node.rb +93 -0
  120. data/lib/mss/s3/tree/node.rb +21 -0
  121. data/lib/mss/s3/tree/parent.rb +86 -0
  122. data/lib/mss/s3/tree.rb +115 -0
  123. data/lib/mss/s3/uploaded_part.rb +81 -0
  124. data/lib/mss/s3/uploaded_part_collection.rb +83 -0
  125. data/lib/mss/s3/website_configuration.rb +101 -0
  126. data/lib/mss/s3.rb +161 -0
  127. data/lib/mss/version.rb +16 -0
  128. data/lib/mss-sdk.rb +2 -0
  129. data/lib/mss.rb +14 -0
  130. data/rails/init.rb +14 -0
  131. metadata +201 -0
@@ -0,0 +1,23 @@
1
+ # Copyright 2011-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License"). You
4
+ # may not use this file except in compliance with the License. A copy of
5
+ # the License is located at
6
+ #
7
+ #
8
+ # or in the "license" file accompanying this file. This file is
9
+ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
10
+ # ANY KIND, either express or implied. See the License for the specific
11
+ # language governing permissions and limitations under the License.
12
+
13
+ module MSS
14
+ module Core
15
+
16
+ # @api private
17
+ module RESTErrorParser
18
+
19
+
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,39 @@
1
+ # Copyright 2011-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License"). You
4
+ # may not use this file except in compliance with the License. A copy of
5
+ # the License is located at
6
+ #
7
+ #
8
+ # or in the "license" file accompanying this file. This file is
9
+ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
10
+ # ANY KIND, either express or implied. See the License for the specific
11
+ # language governing permissions and limitations under the License.
12
+
13
+ module MSS
14
+ module Core
15
+ class RESTJSONClient < Core::Client
16
+
17
+ protected
18
+
19
+ def self.request_builder_for api_config, operation
20
+ Core::RESTRequestBuilder.new(operation, :format => :json)
21
+ end
22
+
23
+ def self.response_parser_for api_config, operation
24
+ Core::RESTResponseParser.new(operation, :format => :json)
25
+ end
26
+
27
+ def extract_error_details response
28
+ if
29
+ response.http_response.status >= 300 and
30
+ body = response.http_response.body and
31
+ json = (::JSON.load(body) rescue nil)
32
+ then
33
+ [json['code'], json['message']]
34
+ end
35
+ end
36
+
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,153 @@
1
+ # Copyright 2011-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License"). You
4
+ # may not use this file except in compliance with the License. A copy of
5
+ # the License is located at
6
+ #
7
+ #
8
+ # or in the "license" file accompanying this file. This file is
9
+ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
10
+ # ANY KIND, either express or implied. See the License for the specific
11
+ # language governing permissions and limitations under the License.
12
+
13
+ module MSS
14
+ module Core
15
+
16
+ # Given a hash of request options, a REST::RequestHandler can
17
+ # populate a Core::Http::Request object.
18
+ class RESTRequestBuilder
19
+
20
+ # @api private
21
+ def initialize operation, options = {}
22
+
23
+ @http = operation[:http]
24
+ @rules = operation[:inputs]
25
+
26
+ @validator = Options::Validator.new(@rules)
27
+
28
+ @serializer =
29
+ case options[:format]
30
+ when :xml
31
+ namespace = options[:xmlnamespace]
32
+ name = operation[:name]
33
+ Options::XMLSerializer.new(namespace, name, operation)
34
+ when :json
35
+ Options::JSONSerializer.new(@rules, @http[:request_payload])
36
+ else
37
+ raise ArgumentError, "unhandled format: #{options[:format]}"
38
+ end
39
+
40
+ end
41
+
42
+ # Populates a Http::Request with the following:
43
+ #
44
+ # * HTTP method
45
+ # * URI
46
+ # * headers
47
+ # * body
48
+ #
49
+ # @param [Http::Request] request
50
+ #
51
+ # @param [Hash] params The hash of request options provided
52
+ # to the client request method. This will be used to populate
53
+ # the headers, uri and body.
54
+ #
55
+ # @raise [ArgumentError] Raises ArgumentError when any of the
56
+ # request options are invalid (wrong type, missing, unknown, etc).
57
+ #
58
+ def populate_request request, params
59
+ params = @validator.validate!(params)
60
+ populate_method(request)
61
+ populate_uri(request, params)
62
+ populate_headers(request, params)
63
+ populate_body(request, params)
64
+ end
65
+
66
+ private
67
+
68
+ def populate_method request
69
+ request.http_method = @http[:verb]
70
+ end
71
+
72
+ def populate_uri request, params
73
+ request.uri = extract_uri(params)
74
+ end
75
+
76
+ def populate_headers request, params
77
+ extract_headers(params).each_pair do |header_name, header_value|
78
+ request.headers[header_name] = header_value
79
+ end
80
+ end
81
+
82
+ # @param [Hash] params
83
+ # @return [String]
84
+ def extract_uri params
85
+
86
+ path, querystring = @http[:uri].split(/\?/)
87
+
88
+ uri = path.gsub(/:\w+/) do |param_name|
89
+ if param = params.delete(param_name.sub(/^:/, '').to_sym)
90
+ UriEscape.escape(param)
91
+ else
92
+ raise ArgumentError, "missing required option #{param_name}"
93
+ end
94
+ end
95
+
96
+ querystring_parts = []
97
+ querystring.to_s.split(/&|;/).each do |part|
98
+ param_name = part.match(/:(\w+)/)[1]
99
+ if param = params.delete(param_name.to_sym)
100
+ param = UriEscape.escape(param)
101
+ querystring_parts << part.sub(/:#{param_name}/, param)
102
+ end
103
+ end
104
+
105
+ unless querystring_parts.empty?
106
+ uri << "?#{querystring_parts.join('&')}"
107
+ end
108
+
109
+ uri
110
+
111
+ end
112
+
113
+ # @param [Hash] params
114
+ # @return [Hash]
115
+ def extract_headers params
116
+ headers = {}
117
+ (@http[:request_headers] || {}).each_pair do |param,header|
118
+ headers[header] = params[param] if params.key?(param)
119
+ end
120
+ headers
121
+ end
122
+
123
+ # @param [Hash] params
124
+ # @return [String,nil]
125
+ def populate_body request, params
126
+ if params.empty?
127
+ request.body = nil
128
+ elsif payload = streaming_param # streaming request
129
+ request.body_stream = params[payload]
130
+ request.headers['Content-Length'] = size(params[payload])
131
+ else
132
+ request.body = @serializer.serialize(params)
133
+ end
134
+ end
135
+
136
+ def size(payload)
137
+ if payload.respond_to?(:path) && payload.path
138
+ File.size(payload.path)
139
+ else
140
+ payload.size
141
+ end
142
+ end
143
+
144
+ def streaming_param
145
+ if payload = @http[:request_payload]
146
+ @rules[payload][:type] == :blob ? payload : nil
147
+ end
148
+ end
149
+
150
+ end
151
+
152
+ end
153
+ end
@@ -0,0 +1,65 @@
1
+ # Copyright 2011-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License"). You
4
+ # may not use this file except in compliance with the License. A copy of
5
+ # the License is located at
6
+ #
7
+ #
8
+ # or in the "license" file accompanying this file. This file is
9
+ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
10
+ # ANY KIND, either express or implied. See the License for the specific
11
+ # language governing permissions and limitations under the License.
12
+
13
+ module MSS
14
+ module Core
15
+
16
+ # Given a hash of request options, a REST::RequestHandler can
17
+ # populate a Core::Http::Request object.
18
+ class RESTResponseParser
19
+
20
+ # @api private
21
+ def initialize operation, options
22
+ @http = operation[:http]
23
+ @parser =
24
+ case options[:format]
25
+ when :xml then XML::Parser.new(operation[:outputs])
26
+ when :json then Core::JSONParser.new(operation[:outputs])
27
+ else raise "unhandled format: #{options[:format].inspect}"
28
+ end
29
+ end
30
+
31
+ # Given a response object, this method extract and returns a
32
+ # hash of response data.
33
+ # @param [Response] response
34
+ # @return [Hash]
35
+ def extract_data response
36
+
37
+ if payload = @http[:response_payload]
38
+ data = { payload => response.http_response.body }
39
+ else
40
+ data = @parser.parse(response.http_response.body)
41
+ end
42
+
43
+ if header = response.http_response.headers['x-amzn-requestid']
44
+ data[:request_id] = [header].flatten.first
45
+ end
46
+
47
+ # extract headers and insert into response
48
+ (@http[:response_headers] || {}).each_pair do |name,header_name|
49
+ if header = response.http_response.headers[header_name.downcase]
50
+ data[name] = [header].flatten.first
51
+ end
52
+ end
53
+
54
+ data
55
+
56
+ end
57
+
58
+ def simulate
59
+ {}
60
+ end
61
+
62
+ end
63
+
64
+ end
65
+ end
@@ -0,0 +1,46 @@
1
+ # Copyright 2011-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License"). You
4
+ # may not use this file except in compliance with the License. A copy of
5
+ # the License is located at
6
+ #
7
+ #
8
+ # or in the "license" file accompanying this file. This file is
9
+ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
10
+ # ANY KIND, either express or implied. See the License for the specific
11
+ # language governing permissions and limitations under the License.
12
+
13
+ module MSS
14
+ module Core
15
+ # @since 1.8.0
16
+ class RESTXMLClient < Core::Client
17
+
18
+ protected
19
+
20
+ def self.request_builder_for api_config, operation
21
+ RESTRequestBuilder.new(operation,
22
+ :format => :xml,
23
+ :xmlnamespace => api_config[:namespace])
24
+ end
25
+
26
+ def self.response_parser_for api_config, operation
27
+ RESTResponseParser.new(operation, :format => :xml)
28
+ end
29
+
30
+ def extract_error_details response
31
+ if
32
+ response.http_response.status >= 300 and
33
+ body = response.http_response.body and
34
+ error = errors_module::GRAMMAR.parse(body) and
35
+ error[:code]
36
+ then
37
+ [error[:code], error[:message]]
38
+ end
39
+ end
40
+
41
+ end
42
+
43
+ # @deprecated Use RESTXMLClient instead.
44
+ RESTClient = RESTXMLClient
45
+ end
46
+ end
@@ -0,0 +1,82 @@
1
+ # Copyright 2011-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License"). You
4
+ # may not use this file except in compliance with the License. A copy of
5
+ # the License is located at
6
+ #
7
+ #
8
+ # or in the "license" file accompanying this file. This file is
9
+ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
10
+ # ANY KIND, either express or implied. See the License for the specific
11
+ # language governing permissions and limitations under the License.
12
+
13
+ module MSS
14
+ module Core
15
+
16
+ module ServiceInterface
17
+
18
+ def self.included base
19
+
20
+ base.send(:attr_reader, :config)
21
+ base.send(:attr_reader, :client)
22
+
23
+ base.module_eval('module Errors; end')
24
+
25
+ unless base::Errors.include?(Errors)
26
+ base::Errors.module_eval { include Errors }
27
+ end
28
+
29
+ MSS::Core::MetaUtils.extend(base) do
30
+
31
+ # @api private
32
+ def endpoint_prefix prefix = nil, options = {}
33
+ if prefix
34
+ @endpoint_prefix = prefix
35
+ @global_endpoint = !!options[:global]
36
+ end
37
+ @endpoint_prefix
38
+ end
39
+
40
+ # @api private
41
+ def global_endpoint?
42
+ @global_endpoint
43
+ end
44
+
45
+ def regions
46
+ RegionCollection.new(:service => self)
47
+ end
48
+
49
+ end
50
+
51
+ end
52
+
53
+ # Returns a new interface object for this service. You can override
54
+ # any of the global configuration parameters by passing them in as
55
+ # hash options. They are merged with MSS.config or merged
56
+ # with the provided `:config` object.
57
+ #
58
+ # @ec2 = MSS::EC2.new(:max_retries => 2)
59
+ #
60
+ # @see MSS::Cofiguration
61
+ #
62
+ # @param [Hash] options
63
+ #
64
+ # @option options [Configuration] :config An MSS::Configuration
65
+ # object to initialize this service interface object with. Defaults
66
+ # to MSS.config when not provided.
67
+ #
68
+ def initialize options = {}
69
+ options = options.dup
70
+ @config = (options.delete(:config) || MSS.config)
71
+ @config = @config.with(options)
72
+ @client = @config.send(Inflection.ruby_name(self.class.name.split('::').last) + '_client')
73
+ end
74
+
75
+ # @return [String]
76
+ def inspect
77
+ "<#{self.class}>"
78
+ end
79
+
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,45 @@
1
+ # Copyright 2011-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License"). You
4
+ # may not use this file except in compliance with the License. A copy of
5
+ # the License is located at
6
+ #
7
+ #
8
+ # or in the "license" file accompanying this file. This file is
9
+ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
10
+ # ANY KIND, either express or implied. See the License for the specific
11
+ # language governing permissions and limitations under the License.
12
+
13
+ require 'base64'
14
+
15
+ module MSS
16
+ module Core
17
+ module Signers
18
+ # @api private
19
+ module Base
20
+
21
+ # Signs a string using the credentials stored in memory.
22
+ # @param [String] secret Usually an MSS secret access key.
23
+ # @param [String] string_to_sign The string to sign.
24
+ # @param [String] digest_method The digest method to use when
25
+ # computing the HMAC digest.
26
+ # @return [String] Returns the computed signature.
27
+ def sign secret, string_to_sign, digest_method = 'sha256'
28
+ Base64.encode64(hmac(secret, string_to_sign, digest_method)).strip
29
+ end
30
+ module_function :sign
31
+
32
+ # Computes an HMAC digest of the passed string.
33
+ # @param [String] key
34
+ # @param [String] value
35
+ # @param [String] digest ('sha256')
36
+ # @return [String]
37
+ def hmac key, value, digest = 'sha256'
38
+ OpenSSL::HMAC.digest(OpenSSL::Digest.new(digest), key, value)
39
+ end
40
+ module_function :hmac
41
+
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,55 @@
1
+ # Copyright 2011-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License"). You
4
+ # may not use this file except in compliance with the License. A copy of
5
+ # the License is located at
6
+ #
7
+ #
8
+ # or in the "license" file accompanying this file. This file is
9
+ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
10
+ # ANY KIND, either express or implied. See the License for the specific
11
+ # language governing permissions and limitations under the License.
12
+
13
+ require 'time'
14
+
15
+ module MSS
16
+ module Core
17
+ module Signers
18
+ class CloudFront
19
+
20
+ include Base
21
+
22
+ # @param [CredentialProviders::Provider] credentials
23
+ def initialize credentials
24
+ @credentials = credentials
25
+ end
26
+
27
+ # @return [CredentialProviders::Provider]
28
+ attr_reader :credentials
29
+
30
+ # @param [Http::Request] req
31
+ # @return [Http::Request]
32
+ def sign_request req
33
+ req.headers['x-amz-security-token'] = credentials.session_token if
34
+ credentials.session_token
35
+ req.headers['authorization'] =
36
+ "AWS #{credentials.access_key_id}:#{signature(req)}"
37
+ req
38
+ end
39
+
40
+ private
41
+
42
+ # @param [Http::Request] req
43
+ def signature req
44
+ sign(credentials.secret_access_key, string_to_sign(req), 'sha1')
45
+ end
46
+
47
+ # @param [Http::Request] req
48
+ def string_to_sign req
49
+ req.headers['date'] ||= Time.now.httpdate
50
+ end
51
+
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,158 @@
1
+ # Copyright 2011-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License"). You
4
+ # may not use this file except in compliance with the License. A copy of
5
+ # the License is located at
6
+ #
7
+ #
8
+ # or in the "license" file accompanying this file. This file is
9
+ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
10
+ # ANY KIND, either express or implied. See the License for the specific
11
+ # language governing permissions and limitations under the License.
12
+
13
+ module MSS
14
+ module Core
15
+ module Signers
16
+ # @api private
17
+ class S3
18
+
19
+ SUB_RESOURCES = %w(
20
+ acl location logging notification partNumber policy
21
+ requestPayment torrent uploadId uploads versionId
22
+ versioning versions restore delete lifecycle tagging cors
23
+ website
24
+ )
25
+
26
+ QUERY_PARAMS = %w(
27
+ response-content-type response-content-language
28
+ response-expires response-cache-control
29
+ response-content-disposition response-content-encoding
30
+ )
31
+
32
+ # @param [CredentialProviders::Provider] credentials
33
+ def initialize credentials
34
+ @credentials = credentials
35
+ end
36
+
37
+ # @return [CredentialProviders::Provider]
38
+ attr_reader :credentials
39
+
40
+ # @param [Http::Request] req
41
+ # @return [Http::Request]
42
+ def sign_request req
43
+ if token = credentials.session_token
44
+ req.headers["x-amz-security-token"] = token
45
+ end
46
+ req.headers["authorization"] = authorization(req)
47
+ end
48
+
49
+ private
50
+
51
+ def authorization req
52
+ "AWS #{credentials.access_key_id}:#{signature(req)}"
53
+ end
54
+
55
+ def signature req
56
+ secret = credentials.secret_access_key
57
+ signature = self.class.string_to_sign(req)
58
+ signature = Base.sign(credentials.secret_access_key, signature, 'sha1')
59
+ URI.escape(signature)
60
+ end
61
+
62
+ class << self
63
+
64
+ # From the S3 developer guide:
65
+ #
66
+ # StringToSign =
67
+ # HTTP-Verb ` "\n" `
68
+ # content-md5 ` "\n" `
69
+ # content-type ` "\n" `
70
+ # date ` "\n" `
71
+ # CanonicalizedAmzHeaders + CanonicalizedResource;
72
+ #
73
+ def string_to_sign req
74
+ [
75
+ req.http_method,
76
+ req.headers.values_at('content-md5', 'content-type').join("\n"),
77
+ signing_string_date(req),
78
+ canonicalized_headers(req),
79
+ canonicalized_resource(req),
80
+ ].flatten.compact.join("\n")
81
+ end
82
+
83
+ def signing_string_date req
84
+ # if a date is provided via x-amz-date then we should omit the
85
+ # Date header from the signing string (should appear as a blank line)
86
+ if req.headers.detect{|k,v| k.to_s =~ /^x-amz-date$/i }
87
+ ''
88
+ else
89
+ req.headers['date'] ||= Time.now.httpdate
90
+ end
91
+ end
92
+
93
+ # CanonicalizedAmzHeaders
94
+ #
95
+ # See the developer guide for more information on how this element
96
+ # is generated.
97
+ #
98
+ def canonicalized_headers req
99
+ x_amz = req.headers.select{|k, v| k.to_s =~ /^x-amz-/i }
100
+ x_amz = x_amz.collect{|k, v| [k.downcase, v] }
101
+ x_amz = x_amz.sort_by{|k, v| k }
102
+ x_amz = x_amz.collect{|k, v| "#{k}:#{v.to_s.strip}" }.join("\n")
103
+ x_amz == '' ? nil : x_amz
104
+ end
105
+
106
+ # From the S3 developer guide
107
+ #
108
+ # CanonicalizedResource =
109
+ # [ "/" ` Bucket ] `
110
+ # <HTTP-Request-URI, protocol name up to the querystring> +
111
+ # [ sub-resource, if present. e.g. "?acl", "?location",
112
+ # "?logging", or "?torrent"];
113
+ #
114
+ # @api private
115
+ def canonicalized_resource req
116
+
117
+ parts = []
118
+
119
+ # virtual hosted-style requests require the hostname to appear
120
+ # in the canonicalized resource prefixed by a forward slash.
121
+ if
122
+ MSS::S3::Client.dns_compatible_bucket_name?(req.bucket) and
123
+ !req.path_style?
124
+ then
125
+ parts << "/#{req.bucket}"
126
+ end
127
+
128
+ # all requests require the portion of the un-decoded uri up to
129
+ # but not including the query string
130
+ parts << req.path
131
+
132
+ # lastly any sub resource querystring params need to be appened
133
+ # in lexigraphical ordered joined by '&' and prefixed by '?'
134
+ params =
135
+ sub_resource_params(req) +
136
+ query_parameters_for_signature(req)
137
+
138
+ unless params.empty?
139
+ parts << '?'
140
+ parts << params.sort.collect{|p| p.to_s }.join('&')
141
+ end
142
+
143
+ parts.join
144
+ end
145
+
146
+ def sub_resource_params req
147
+ req.params.select{|p| SUB_RESOURCES.include?(p.name) }
148
+ end
149
+
150
+ def query_parameters_for_signature req
151
+ req.params.select { |p| QUERY_PARAMS.include?(p.name) }
152
+ end
153
+
154
+ end
155
+ end
156
+ end
157
+ end
158
+ end