aws-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 (205) hide show
  1. data/.yardopts +6 -0
  2. data/LICENSE.txt +171 -0
  3. data/NOTICE.txt +2 -0
  4. data/README.rdoc +189 -0
  5. data/lib/aws-sdk.rb +14 -0
  6. data/lib/aws.rb +63 -0
  7. data/lib/aws/api_config.rb +45 -0
  8. data/lib/aws/api_config/.document +0 -0
  9. data/lib/aws/api_config/EC2-2011-02-28.yml +2314 -0
  10. data/lib/aws/api_config/SNS-2010-03-31.yml +171 -0
  11. data/lib/aws/api_config/SQS-2009-02-01.yml +161 -0
  12. data/lib/aws/api_config/SimpleDB-2009-04-15.yml +278 -0
  13. data/lib/aws/api_config/SimpleEmailService-2010-12-01.yml +147 -0
  14. data/lib/aws/api_config_transform.rb +32 -0
  15. data/lib/aws/async_handle.rb +90 -0
  16. data/lib/aws/authorize_v2.rb +37 -0
  17. data/lib/aws/authorize_v3.rb +37 -0
  18. data/lib/aws/base_client.rb +524 -0
  19. data/lib/aws/cacheable.rb +92 -0
  20. data/lib/aws/common.rb +228 -0
  21. data/lib/aws/configurable.rb +36 -0
  22. data/lib/aws/configuration.rb +272 -0
  23. data/lib/aws/configured_client_methods.rb +81 -0
  24. data/lib/aws/configured_grammars.rb +65 -0
  25. data/lib/aws/configured_option_grammars.rb +46 -0
  26. data/lib/aws/configured_xml_grammars.rb +47 -0
  27. data/lib/aws/default_signer.rb +38 -0
  28. data/lib/aws/ec2.rb +321 -0
  29. data/lib/aws/ec2/attachment.rb +149 -0
  30. data/lib/aws/ec2/attachment_collection.rb +57 -0
  31. data/lib/aws/ec2/availability_zone.rb +80 -0
  32. data/lib/aws/ec2/availability_zone_collection.rb +47 -0
  33. data/lib/aws/ec2/block_device_mappings.rb +53 -0
  34. data/lib/aws/ec2/client.rb +54 -0
  35. data/lib/aws/ec2/client/xml.rb +127 -0
  36. data/lib/aws/ec2/collection.rb +39 -0
  37. data/lib/aws/ec2/config_transform.rb +63 -0
  38. data/lib/aws/ec2/elastic_ip.rb +107 -0
  39. data/lib/aws/ec2/elastic_ip_collection.rb +85 -0
  40. data/lib/aws/ec2/errors.rb +29 -0
  41. data/lib/aws/ec2/filtered_collection.rb +65 -0
  42. data/lib/aws/ec2/has_permissions.rb +46 -0
  43. data/lib/aws/ec2/image.rb +245 -0
  44. data/lib/aws/ec2/image_collection.rb +235 -0
  45. data/lib/aws/ec2/instance.rb +515 -0
  46. data/lib/aws/ec2/instance_collection.rb +276 -0
  47. data/lib/aws/ec2/key_pair.rb +86 -0
  48. data/lib/aws/ec2/key_pair_collection.rb +102 -0
  49. data/lib/aws/ec2/permission_collection.rb +177 -0
  50. data/lib/aws/ec2/region.rb +81 -0
  51. data/lib/aws/ec2/region_collection.rb +55 -0
  52. data/lib/aws/ec2/request.rb +27 -0
  53. data/lib/aws/ec2/reserved_instances.rb +50 -0
  54. data/lib/aws/ec2/reserved_instances_collection.rb +44 -0
  55. data/lib/aws/ec2/reserved_instances_offering.rb +55 -0
  56. data/lib/aws/ec2/reserved_instances_offering_collection.rb +43 -0
  57. data/lib/aws/ec2/resource.rb +340 -0
  58. data/lib/aws/ec2/resource_tag_collection.rb +218 -0
  59. data/lib/aws/ec2/security_group.rb +246 -0
  60. data/lib/aws/ec2/security_group/ip_permission.rb +70 -0
  61. data/lib/aws/ec2/security_group/ip_permission_collection.rb +59 -0
  62. data/lib/aws/ec2/security_group_collection.rb +132 -0
  63. data/lib/aws/ec2/snapshot.rb +138 -0
  64. data/lib/aws/ec2/snapshot_collection.rb +90 -0
  65. data/lib/aws/ec2/tag.rb +88 -0
  66. data/lib/aws/ec2/tag_collection.rb +114 -0
  67. data/lib/aws/ec2/tagged_collection.rb +48 -0
  68. data/lib/aws/ec2/tagged_item.rb +87 -0
  69. data/lib/aws/ec2/volume.rb +190 -0
  70. data/lib/aws/ec2/volume_collection.rb +95 -0
  71. data/lib/aws/errors.rb +129 -0
  72. data/lib/aws/http/builtin_handler.rb +69 -0
  73. data/lib/aws/http/curb_handler.rb +123 -0
  74. data/lib/aws/http/handler.rb +77 -0
  75. data/lib/aws/http/httparty_handler.rb +61 -0
  76. data/lib/aws/http/request.rb +136 -0
  77. data/lib/aws/http/request_param.rb +63 -0
  78. data/lib/aws/http/response.rb +75 -0
  79. data/lib/aws/ignore_result_element.rb +38 -0
  80. data/lib/aws/indifferent_hash.rb +86 -0
  81. data/lib/aws/inflection.rb +46 -0
  82. data/lib/aws/lazy_error_classes.rb +64 -0
  83. data/lib/aws/meta_utils.rb +43 -0
  84. data/lib/aws/model.rb +57 -0
  85. data/lib/aws/naming.rb +32 -0
  86. data/lib/aws/option_grammar.rb +544 -0
  87. data/lib/aws/policy.rb +912 -0
  88. data/lib/aws/rails.rb +209 -0
  89. data/lib/aws/record.rb +79 -0
  90. data/lib/aws/record/attribute.rb +94 -0
  91. data/lib/aws/record/attribute_macros.rb +288 -0
  92. data/lib/aws/record/attributes/boolean.rb +49 -0
  93. data/lib/aws/record/attributes/datetime.rb +86 -0
  94. data/lib/aws/record/attributes/float.rb +48 -0
  95. data/lib/aws/record/attributes/integer.rb +68 -0
  96. data/lib/aws/record/attributes/sortable_float.rb +60 -0
  97. data/lib/aws/record/attributes/sortable_integer.rb +95 -0
  98. data/lib/aws/record/attributes/string.rb +69 -0
  99. data/lib/aws/record/base.rb +728 -0
  100. data/lib/aws/record/conversion.rb +38 -0
  101. data/lib/aws/record/dirty_tracking.rb +286 -0
  102. data/lib/aws/record/errors.rb +153 -0
  103. data/lib/aws/record/exceptions.rb +48 -0
  104. data/lib/aws/record/finder_methods.rb +262 -0
  105. data/lib/aws/record/naming.rb +31 -0
  106. data/lib/aws/record/scope.rb +157 -0
  107. data/lib/aws/record/validations.rb +653 -0
  108. data/lib/aws/record/validator.rb +237 -0
  109. data/lib/aws/record/validators/acceptance.rb +51 -0
  110. data/lib/aws/record/validators/block.rb +38 -0
  111. data/lib/aws/record/validators/confirmation.rb +43 -0
  112. data/lib/aws/record/validators/count.rb +108 -0
  113. data/lib/aws/record/validators/exclusion.rb +43 -0
  114. data/lib/aws/record/validators/format.rb +57 -0
  115. data/lib/aws/record/validators/inclusion.rb +56 -0
  116. data/lib/aws/record/validators/length.rb +107 -0
  117. data/lib/aws/record/validators/numericality.rb +138 -0
  118. data/lib/aws/record/validators/presence.rb +45 -0
  119. data/lib/aws/resource_cache.rb +39 -0
  120. data/lib/aws/response.rb +113 -0
  121. data/lib/aws/response_cache.rb +50 -0
  122. data/lib/aws/s3.rb +109 -0
  123. data/lib/aws/s3/access_control_list.rb +252 -0
  124. data/lib/aws/s3/acl_object.rb +266 -0
  125. data/lib/aws/s3/bucket.rb +320 -0
  126. data/lib/aws/s3/bucket_collection.rb +122 -0
  127. data/lib/aws/s3/bucket_version_collection.rb +85 -0
  128. data/lib/aws/s3/client.rb +999 -0
  129. data/lib/aws/s3/client/xml.rb +190 -0
  130. data/lib/aws/s3/data_options.rb +99 -0
  131. data/lib/aws/s3/errors.rb +43 -0
  132. data/lib/aws/s3/multipart_upload.rb +318 -0
  133. data/lib/aws/s3/multipart_upload_collection.rb +78 -0
  134. data/lib/aws/s3/object_collection.rb +159 -0
  135. data/lib/aws/s3/object_metadata.rb +67 -0
  136. data/lib/aws/s3/object_upload_collection.rb +83 -0
  137. data/lib/aws/s3/object_version.rb +141 -0
  138. data/lib/aws/s3/object_version_collection.rb +78 -0
  139. data/lib/aws/s3/paginated_collection.rb +94 -0
  140. data/lib/aws/s3/policy.rb +76 -0
  141. data/lib/aws/s3/prefix_and_delimiter_collection.rb +56 -0
  142. data/lib/aws/s3/prefixed_collection.rb +84 -0
  143. data/lib/aws/s3/presigned_post.rb +504 -0
  144. data/lib/aws/s3/request.rb +198 -0
  145. data/lib/aws/s3/s3_object.rb +794 -0
  146. data/lib/aws/s3/tree.rb +116 -0
  147. data/lib/aws/s3/tree/branch_node.rb +71 -0
  148. data/lib/aws/s3/tree/child_collection.rb +108 -0
  149. data/lib/aws/s3/tree/leaf_node.rb +99 -0
  150. data/lib/aws/s3/tree/node.rb +22 -0
  151. data/lib/aws/s3/tree/parent.rb +90 -0
  152. data/lib/aws/s3/uploaded_part.rb +82 -0
  153. data/lib/aws/s3/uploaded_part_collection.rb +86 -0
  154. data/lib/aws/service_interface.rb +60 -0
  155. data/lib/aws/simple_db.rb +202 -0
  156. data/lib/aws/simple_db/attribute.rb +159 -0
  157. data/lib/aws/simple_db/attribute_collection.rb +227 -0
  158. data/lib/aws/simple_db/client.rb +52 -0
  159. data/lib/aws/simple_db/client/options.rb +34 -0
  160. data/lib/aws/simple_db/client/xml.rb +68 -0
  161. data/lib/aws/simple_db/consistent_read_option.rb +42 -0
  162. data/lib/aws/simple_db/delete_attributes.rb +64 -0
  163. data/lib/aws/simple_db/domain.rb +118 -0
  164. data/lib/aws/simple_db/domain_collection.rb +116 -0
  165. data/lib/aws/simple_db/domain_metadata.rb +112 -0
  166. data/lib/aws/simple_db/errors.rb +46 -0
  167. data/lib/aws/simple_db/expect_condition_option.rb +45 -0
  168. data/lib/aws/simple_db/item.rb +84 -0
  169. data/lib/aws/simple_db/item_collection.rb +594 -0
  170. data/lib/aws/simple_db/item_data.rb +70 -0
  171. data/lib/aws/simple_db/put_attributes.rb +62 -0
  172. data/lib/aws/simple_db/request.rb +27 -0
  173. data/lib/aws/simple_email_service.rb +373 -0
  174. data/lib/aws/simple_email_service/client.rb +39 -0
  175. data/lib/aws/simple_email_service/client/options.rb +24 -0
  176. data/lib/aws/simple_email_service/client/xml.rb +38 -0
  177. data/lib/aws/simple_email_service/email_address_collection.rb +66 -0
  178. data/lib/aws/simple_email_service/errors.rb +29 -0
  179. data/lib/aws/simple_email_service/quotas.rb +64 -0
  180. data/lib/aws/simple_email_service/request.rb +27 -0
  181. data/lib/aws/sns.rb +69 -0
  182. data/lib/aws/sns/client.rb +37 -0
  183. data/lib/aws/sns/client/options.rb +24 -0
  184. data/lib/aws/sns/client/xml.rb +38 -0
  185. data/lib/aws/sns/errors.rb +29 -0
  186. data/lib/aws/sns/policy.rb +49 -0
  187. data/lib/aws/sns/request.rb +27 -0
  188. data/lib/aws/sns/subscription.rb +100 -0
  189. data/lib/aws/sns/subscription_collection.rb +84 -0
  190. data/lib/aws/sns/topic.rb +384 -0
  191. data/lib/aws/sns/topic_collection.rb +70 -0
  192. data/lib/aws/sns/topic_subscription_collection.rb +58 -0
  193. data/lib/aws/sqs.rb +70 -0
  194. data/lib/aws/sqs/client.rb +38 -0
  195. data/lib/aws/sqs/client/xml.rb +36 -0
  196. data/lib/aws/sqs/errors.rb +33 -0
  197. data/lib/aws/sqs/policy.rb +50 -0
  198. data/lib/aws/sqs/queue.rb +507 -0
  199. data/lib/aws/sqs/queue_collection.rb +105 -0
  200. data/lib/aws/sqs/received_message.rb +184 -0
  201. data/lib/aws/sqs/received_sns_message.rb +112 -0
  202. data/lib/aws/sqs/request.rb +44 -0
  203. data/lib/aws/xml_grammar.rb +923 -0
  204. data/rails/init.rb +15 -0
  205. metadata +298 -0
@@ -0,0 +1,912 @@
1
+ # Copyright 2011 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
+ # http://aws.amazon.com/apache2.0/
8
+ #
9
+ # or in the "license" file accompanying this file. This file is
10
+ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
11
+ # ANY KIND, either express or implied. See the License for the specific
12
+ # language governing permissions and limitations under the License.
13
+
14
+ require 'aws/inflection'
15
+ require 'uuidtools'
16
+ require 'date'
17
+
18
+ module AWS
19
+
20
+ # Represents an access policy for S3 operations and resources. For example:
21
+ #
22
+ # policy = Policy.new do |policy|
23
+ # policy.allow(:actions => ['s3:PutObject'],
24
+ # :resources => "arn:aws:s3:::mybucket/mykey/*",
25
+ # :principals => :any
26
+ # ).where(:acl).is("public-read")
27
+ # end
28
+ #
29
+ # policy.to_json # => '{ "Version":"2008-10-17", ...'
30
+ #
31
+ # @see #initialize More ways to construct a policy.
32
+ # @see http://docs.amazonwebservices.com/AmazonS3/latest/dev/AccessPolicyLanguage_UseCases_s3_a.html Example policies (in JSON).
33
+ class Policy
34
+
35
+ # @see Statement
36
+ # @return [Array] An array of policy statements.
37
+ attr_reader :statements
38
+
39
+ # @return [String] The version of the policy language used in this
40
+ # policy object.
41
+ attr_reader :version
42
+
43
+ # @return [String] A unique ID for the policy.
44
+ attr_reader :id
45
+
46
+ class Statement; end
47
+
48
+ # Constructs a policy. There are a few different ways to
49
+ # build a policy:
50
+ #
51
+ # * With hash arguments:
52
+ #
53
+ # Policy.new(:statements => [
54
+ # { :effect => :allow,
55
+ # :actions => :all,
56
+ # :principals => ["abc123"],
57
+ # :resources => "mybucket/mykey"
58
+ # }
59
+ # ])
60
+ #
61
+ # * From a JSON policy document:
62
+ #
63
+ # Policy.from_json(policy_json_string)
64
+ #
65
+ # * With a block:
66
+ #
67
+ # Policy.new do |policy|
68
+ #
69
+ # policy.allow(
70
+ # :actions => ['s3:PutObject'],
71
+ # :resources => "arn:aws:s3:::mybucket/mykey/*",
72
+ # :principals => :any
73
+ # ).where(:acl).is("public-read")
74
+ #
75
+ # end
76
+ #
77
+ def initialize(opts = {})
78
+ @statements = opts.values_at(:statements, "Statement").select do |a|
79
+ a.kind_of?(Array)
80
+ end.flatten.map do |stmt|
81
+ self.class::Statement.new(stmt)
82
+ end
83
+
84
+ if opts.has_key?(:id) or opts.has_key?("Id")
85
+ @id = opts[:id] || opts["Id"]
86
+ else
87
+ @id = UUIDTools::UUID.timestamp_create.to_s
88
+ end
89
+ if opts.has_key?(:version) or opts.has_key?("Version")
90
+ @version = opts[:version] || opts["Version"]
91
+ else
92
+ @version = "2008-10-17"
93
+ end
94
+
95
+ yield(self) if block_given?
96
+ end
97
+
98
+ # @return [Boolean] Returns true if the two policies are the same.
99
+ def ==(other)
100
+ if other.kind_of?(AWS::Policy)
101
+ self.hash_without_ids == other.hash_without_ids
102
+ else
103
+ false
104
+ end
105
+ end
106
+ alias_method :eql?, :==
107
+
108
+ # Removes the ids from the policy and its statements for the purpose
109
+ # of comparing two policies for equivilence.
110
+ # @return [Hash] Returns the policy as a hash with no ids
111
+ # @private
112
+ def hash_without_ids
113
+ hash = self.to_h
114
+ hash.delete('Id')
115
+ hash['Statement'].each do |statement|
116
+ statement.delete('Sid')
117
+ end
118
+ hash
119
+ end
120
+ protected :hash_without_ids
121
+
122
+ # Returns a hash representation of the policy; the
123
+ # following statements are equivalent:
124
+ #
125
+ # policy.to_h.to_json
126
+ # policy.to_json
127
+ #
128
+ # @return [Hash]
129
+ def to_h
130
+ {
131
+ "Version" => version,
132
+ "Id" => id,
133
+ "Statement" => statements.map { |st| st.to_h }
134
+ }
135
+ end
136
+
137
+ # @return [String] a JSON representation of the policy.
138
+ def to_json
139
+ to_h.to_json
140
+ end
141
+
142
+ # Constructs a policy from a JSON representation.
143
+ # @see #initialize
144
+ # @return [Policy] Returns a Policy object constructed by parsing
145
+ # the passed JSON policy.
146
+ def self.from_json(json)
147
+ new(JSON.parse(json))
148
+ end
149
+
150
+ # Convenient syntax for expressing operators in statement
151
+ # condition blocks. For example, the following:
152
+ #
153
+ # policy.allow.where(:s3_prefix).not("forbidden").
154
+ # where(:current_time).lte(Date.today+1)
155
+ #
156
+ # is equivalent to:
157
+ #
158
+ # conditions = Policy::ConditionBlock.new
159
+ # conditions.add(:not, :s3_prefix, "forbidden")
160
+ # conditions.add(:lte, :current_time, Date.today+1)
161
+ # policy.allow(:conditions => conditions)
162
+ #
163
+ # @see ConditionBlock#add
164
+ class OperatorBuilder
165
+
166
+ # @private
167
+ def initialize(condition_builder, key)
168
+ @condition_builder = condition_builder
169
+ @key = key
170
+ end
171
+
172
+ def method_missing(m, *values)
173
+ @condition_builder.conditions.add(m, @key, *values)
174
+ @condition_builder
175
+ end
176
+
177
+ end
178
+
179
+ # Convenient syntax for adding conditions to a statement.
180
+ # @see Policy#allow
181
+ # @see Policy#deny
182
+ class ConditionBuilder
183
+
184
+ # @return [Array] Returns an array of policy conditions.
185
+ attr_reader :conditions
186
+
187
+ # @private
188
+ def initialize(conditions)
189
+ @conditions = conditions
190
+ end
191
+
192
+ # Adds a condition for the given key. For example:
193
+ #
194
+ # policy.allow(...).where(:current_time).lte(Date.today + 1)
195
+ #
196
+ # @return [OperatorBuilder]
197
+ def where(key, operator = nil, *values)
198
+ if operator
199
+ @conditions.add(operator, key, *values)
200
+ self
201
+ else
202
+ OperatorBuilder.new(self, key)
203
+ end
204
+ end
205
+
206
+ end
207
+
208
+ # Convenience method for constructing a new statement with the
209
+ # "Allow" effect and adding it to the policy. For example:
210
+ #
211
+ # policy.allow(:actions => [:put_object],
212
+ # :principals => :any,
213
+ # :resources => "mybucket/mykey/*").
214
+ # where(:acl).is("public-read")
215
+ #
216
+ # @option (see Statement#initialize)
217
+ # @see Statement#initialize
218
+ # @return [ConditionBuilder]
219
+ def allow(opts = {})
220
+ stmt = self.class::Statement.new(opts.merge(:effect => :allow))
221
+ statements << stmt
222
+ ConditionBuilder.new(stmt.conditions)
223
+ end
224
+
225
+ # Convenience method for constructing a new statement with the
226
+ # "Deny" effect and adding it to the policy. For example:
227
+ #
228
+ # policy.deny(
229
+ # :actions => [:put_object],
230
+ # :principals => :any,
231
+ # :resources => "mybucket/mykey/*"
232
+ # ).where(:acl).is("public-read")
233
+ #
234
+ # @param (see Statement#initialize)
235
+ # @see Statement#initialize
236
+ # @return [ConditionBuilder]
237
+ def deny(opts = {})
238
+ stmt = self.class::Statement.new(opts.merge(:effect => :deny))
239
+ statements << stmt
240
+ ConditionBuilder.new(stmt.conditions)
241
+ end
242
+
243
+ # Represents the condition block of a policy. In JSON,
244
+ # condition blocks look like this:
245
+ #
246
+ # { "StringLike": { "s3:prefix": ["photos/*", "photos.html"] } }
247
+ #
248
+ # ConditionBlock lets you specify conditions like the above
249
+ # example using the add method, for example:
250
+ #
251
+ # conditions.add(:like, :s3_prefix, "photos/*", "photos.html")
252
+ #
253
+ # See the add method documentation for more details about how
254
+ # to specify keys and operators.
255
+ #
256
+ # This class also provides a convenient way to query a
257
+ # condition block to see what operators, keys, and values it
258
+ # has. For example, consider the following condition block
259
+ # (in JSON):
260
+ #
261
+ # {
262
+ # "StringEquals": {
263
+ # "s3:prefix": "photos/index.html"
264
+ # },
265
+ # "DateEquals": {
266
+ # "aws:CurrentTime": ["2010-10-12", "2011-01-02"]
267
+ # },
268
+ # "NumericEquals": {
269
+ # "s3:max-keys": 10
270
+ # }
271
+ # }
272
+ #
273
+ # You can get access to the condition data using #[], #keys,
274
+ # #operators, and #values -- for example:
275
+ #
276
+ # conditions["DateEquals"]["aws:CurrentTime"].values
277
+ # # => ["2010-10-12", "2011-01-02"]
278
+ #
279
+ # You can also perform more sophisticated queries, like this
280
+ # one:
281
+ #
282
+ # conditions[:is].each do |equality_conditions|
283
+ # equality_conditions.keys.each do |key|
284
+ # puts("#{key} may be any of: " +
285
+ # equality_conditions[key].values.join(" ")
286
+ # end
287
+ # end
288
+ #
289
+ # This would print the following lines:
290
+ #
291
+ # s3:prefix may be any of: photos/index.html
292
+ # aws:CurrentTime may be any of: 2010-10-12 2011-01-02
293
+ # s3:max-keys may be any of: 10
294
+ #
295
+ class ConditionBlock
296
+
297
+ # @private
298
+ def initialize(conditions = {})
299
+ # filter makes a copy
300
+ @conditions = filter_conditions(conditions)
301
+ end
302
+
303
+ # Adds a condition to the block. This method defines a
304
+ # convenient set of abbreviations for operators based on the
305
+ # type of value passed in. For example:
306
+ #
307
+ # conditions.add(:is, :secure_transport, true)
308
+ #
309
+ # Maps to:
310
+ #
311
+ # { "Bool": { "aws:SecureTransport": true } }
312
+ #
313
+ # While:
314
+ #
315
+ # conditions.add(:is, :s3_prefix, "photos/")
316
+ #
317
+ # Maps to:
318
+ #
319
+ # { "StringEquals": { "s3:prefix": "photos/" } }
320
+ #
321
+ # The following list shows which operators are accepted as
322
+ # symbols and how they are represented in the JSON policy:
323
+ #
324
+ # * +:is+ (StringEquals, NumericEquals, DateEquals, or Bool)
325
+ # * +:like+ (StringLike)
326
+ # * +:not_like+ (StringNotLike)
327
+ # * +:not+ (StringNotEquals, NumericNotEquals, or DateNotEquals)
328
+ # * +:greater_than+, +:gt+ (NumericGreaterThan or DateGreaterThan)
329
+ # * +:greater_than_equals+, +:gte+
330
+ # (NumericGreaterThanEquals or DateGreaterThanEquals)
331
+ # * +:less_than+, +:lt+ (NumericLessThan or DateLessThan)
332
+ # * +:less_than_equals+, +:lte+
333
+ # (NumericLessThanEquals or DateLessThanEquals)
334
+ # * +:is_ip_address+ (IpAddress)
335
+ # * +:not_ip_address+ (NotIpAddress)
336
+ # * +:is_arn+ (ArnEquals)
337
+ # * +:not_arn+ (ArnNotEquals)
338
+ # * +:is_arn_like+ (ArnLike)
339
+ # * +:not_arn_like+ (ArnNotLike)
340
+ #
341
+ # @param [Symbol or String] operator The operator used to
342
+ # compare the key with the value. See above for valid
343
+ # values and their interpretations.
344
+ #
345
+ # @param [Symbol or String] key The key to compare. Symbol
346
+ # keys are inflected to match AWS conventions. By
347
+ # default, the key is assumed to be in the "aws"
348
+ # namespace, but if you prefix the symbol name with "s3_"
349
+ # it will be sent in the "s3" namespace. For example,
350
+ # +:s3_prefix+ is sent as "s3:prefix" while
351
+ # +:secure_transport+ is sent as "aws:SecureTransport".
352
+ # See
353
+ # http://docs.amazonwebservices.com/AmazonS3/latest/dev/UsingResOpsConditions.html
354
+ # for a list of the available keys for each action in S3.
355
+ #
356
+ # @param value The value to compare against.
357
+ # This can be:
358
+ # * a String
359
+ # * a number
360
+ # * a Date, DateTime, or Time
361
+ # * a boolean value
362
+ # This method does not attempt to validate that the values
363
+ # are valid for the operators or keys they are used with.
364
+ def add(operator, key, *values)
365
+ if operator.kind_of?(Symbol)
366
+ converted_values = values.map { |v| convert_value(v) }
367
+ else
368
+ converted_values = values
369
+ end
370
+ operator = translate_operator(operator, values.first)
371
+ op = (@conditions[operator] ||= {})
372
+ raise "duplicate #{operator} conditions for #{key}" if op[key]
373
+ op[translate_key(key)] = converted_values
374
+ end
375
+
376
+ # @private
377
+ def to_h
378
+ @conditions
379
+ end
380
+
381
+ # Filters the conditions described in the block, returning a
382
+ # new ConditionBlock that contains only the matching
383
+ # conditions. Each argument is matched against either the
384
+ # keys or the operators in the block, and you can specify
385
+ # the key or operator in any way that's valid for the #add
386
+ # method. Some examples:
387
+ #
388
+ # # all conditions using the StringLike operator
389
+ # conditions["StringLike"]
390
+ #
391
+ # # all conditions using StringEquals, DateEquals, NumericEquals, or Bool
392
+ # conditions[:is]
393
+ #
394
+ # # all conditions on the s3:prefix key
395
+ # conditions["s3:prefix"]
396
+ #
397
+ # # all conditions on the aws:CurrentTime key
398
+ # conditions[:current_time]
399
+ #
400
+ # Multiple conditions are ANDed together, so the following
401
+ # are equivalent:
402
+ #
403
+ # conditions[:s3_prefix][:is]
404
+ # conditions[:is][:s3_prefix]
405
+ # conditions[:s3_prefix, :is]
406
+ #
407
+ # @see #add
408
+ # @return [ConditionBlock] A new set of conditions filtered by the
409
+ # given conditions.
410
+ def [](*args)
411
+ filtered = @conditions
412
+ args.each do |filter|
413
+ type = valid_operator?(filter) ? nil : :key
414
+ filtered = filter_conditions(filtered) do |op, key, value|
415
+ (match, type) = match_triple(filter, type, op, key, value)
416
+ match
417
+ end
418
+ end
419
+ self.class.new(filtered)
420
+ end
421
+
422
+ # @return [Array] Returns an array of operators used in this block.
423
+ def operators
424
+ @conditions.keys
425
+ end
426
+
427
+ # @return [Array] Returns an array of unique keys used in the block.
428
+ def keys
429
+ @conditions.values.map do |keys|
430
+ keys.keys if keys
431
+ end.compact.flatten.uniq
432
+ end
433
+
434
+ # Returns all values used in the block. Note that the
435
+ # values may not all be from the same condition; for example:
436
+ #
437
+ # conditions.add(:like, :user_agent, "mozilla", "explorer")
438
+ # conditions.add(:lt, :s3_max_keys, 12)
439
+ # conditions.values # => ["mozilla", "explorer", 12]
440
+ #
441
+ # @return [Array] Returns an array of values used in this condition block.
442
+ def values
443
+ @conditions.values.map do |keys|
444
+ keys.values
445
+ end.compact.flatten
446
+ end
447
+
448
+ # @private
449
+ protected
450
+ def match_triple(filter, type, op, key, value)
451
+ value = [value].flatten.first
452
+ if type
453
+ target = (type == :operator ? op : key)
454
+ match = send("match_#{type}", filter, target, value)
455
+ else
456
+ if match_operator(filter, op, value)
457
+ match = true
458
+ type = :operator
459
+ elsif match_key(filter, key)
460
+ match = true
461
+ type = :key
462
+ else
463
+ match = false
464
+ end
465
+ end
466
+ [match, type]
467
+ end
468
+
469
+ # @private
470
+ protected
471
+ def match_operator(filter, op, value)
472
+ # dates are the only values that don't come back as native types in JSON
473
+ # but where we use the type as a cue to the operator translation
474
+ value = Date.today if op =~ /^Date/
475
+ translate_operator(filter, value) == op
476
+ end
477
+
478
+ # @private
479
+ protected
480
+ def match_key(filter, key, value = nil)
481
+ translate_key(filter) == key
482
+ end
483
+
484
+ # @private
485
+ protected
486
+ def filter_conditions(conditions = @conditions)
487
+ conditions.inject({}) do |m, (op, keys)|
488
+ m[op] = keys.inject({}) do |m2, (key, value)|
489
+ m2[key] = value if !block_given? or yield(op, key, value)
490
+ m2
491
+ end
492
+ m.delete(op) if m[op].empty?
493
+ m
494
+ end
495
+ end
496
+
497
+ # @private
498
+ protected
499
+ def translate_key(key)
500
+ if key.kind_of?(Symbol)
501
+ if key.to_s =~ /^s3_(.*)$/
502
+ s3_name = $1
503
+ if s3_name == "version_id" or
504
+ s3_name == "location_constraint"
505
+ s3_name = Inflection.class_name(s3_name)
506
+ else
507
+ s3_name.tr!('_', '-')
508
+ end
509
+ "s3:#{s3_name}"
510
+ else
511
+ "aws:#{Inflection.class_name(key.to_s)}"
512
+ end
513
+ else
514
+ key
515
+ end
516
+ end
517
+
518
+ # @private
519
+ MODIFIERS = {
520
+ /_ignoring_case$/ => "IgnoreCase",
521
+ /_equals$/ => "Equals"
522
+ }
523
+
524
+ # @private
525
+ protected
526
+ def valid_operator?(operator)
527
+ translate_operator(operator, "")
528
+ true
529
+ rescue ArgumentError => e
530
+ false
531
+ end
532
+
533
+ # @private
534
+ protected
535
+ def translate_operator(operator, example_value)
536
+ return operator if operator.kind_of?(String)
537
+
538
+ original_operator = operator
539
+ (operator, opts) = strip_modifiers(operator)
540
+
541
+ raise ArgumentError.new("unrecognized operator #{original_operator}") unless
542
+ respond_to?("translate_#{operator}", true)
543
+ send("translate_#{operator}", example_value, opts)
544
+ end
545
+
546
+ # @private
547
+ protected
548
+ def translate_is(example, opts)
549
+ return "Bool" if type_notation(example) == "Bool"
550
+ base_translate(example, "Equals", opts[:ignore_case])
551
+ end
552
+
553
+ # @private
554
+ protected
555
+ def translate_not(example, opts)
556
+ base_translate(example, "NotEquals", opts[:ignore_case])
557
+ end
558
+
559
+ # @private
560
+ protected
561
+ def translate_like(example, opts)
562
+ base_translate(example, "Like")
563
+ end
564
+
565
+ # @private
566
+ protected
567
+ def translate_not_like(example, opts)
568
+ base_translate(example, "NotLike")
569
+ end
570
+
571
+ # @private
572
+ protected
573
+ def translate_less_than(example, opts)
574
+ base_translate(example, "LessThan", opts[:equals])
575
+ end
576
+ alias_method :translate_lt, :translate_less_than
577
+
578
+ # @private
579
+ protected
580
+ def translate_lte(example, opts)
581
+ translate_less_than(example, { :equals => "Equals" })
582
+ end
583
+
584
+ # @private
585
+ protected
586
+ def translate_greater_than(example, opts)
587
+ base_translate(example, "GreaterThan", opts[:equals])
588
+ end
589
+ alias_method :translate_gt, :translate_greater_than
590
+
591
+ # @private
592
+ protected
593
+ def translate_gte(example, opts)
594
+ translate_greater_than(example, { :equals => "Equals" })
595
+ end
596
+
597
+ # @private
598
+ protected
599
+ def translate_is_ip_address(example, opts)
600
+ "IpAddress"
601
+ end
602
+
603
+ # @private
604
+ protected
605
+ def translate_not_ip_address(example, opts)
606
+ "NotIpAddress"
607
+ end
608
+
609
+ # @private
610
+ protected
611
+ def translate_is_arn(example, opts)
612
+ "ArnEquals"
613
+ end
614
+
615
+ # @private
616
+ protected
617
+ def translate_not_arn(example, opts)
618
+ "ArnNotEquals"
619
+ end
620
+
621
+ # @private
622
+ protected
623
+ def translate_is_arn_like(example, opts)
624
+ "ArnLike"
625
+ end
626
+
627
+ # @private
628
+ protected
629
+ def translate_not_arn_like(example, opts)
630
+ "ArnNotLike"
631
+ end
632
+
633
+ # @private
634
+ protected
635
+ def base_translate(example, base_operator, *modifiers)
636
+ "#{type_notation(example)}#{base_operator}#{modifiers.join}"
637
+ end
638
+
639
+ # @private
640
+ protected
641
+ def type_notation(example)
642
+ case example
643
+ when String
644
+ "String"
645
+ when Numeric
646
+ "Numeric"
647
+ when Time, Date
648
+ "Date"
649
+ when true, false
650
+ "Bool"
651
+ end
652
+ end
653
+
654
+ # @private
655
+ protected
656
+ def convert_value(value)
657
+ case value
658
+ when DateTime, Time
659
+ Time.parse(value.to_s).iso8601
660
+ when Date
661
+ value.strftime("%Y-%m-%d")
662
+ else
663
+ value
664
+ end
665
+ end
666
+
667
+ # @private
668
+ protected
669
+ def strip_modifiers(operator)
670
+ opts = {}
671
+ MODIFIERS.each do |(regex, mod)|
672
+ ruby_name = Inflection.ruby_name(mod).to_sym
673
+ opts[ruby_name] = ""
674
+ if operator.to_s =~ regex
675
+ opts[ruby_name] = mod
676
+ operator = operator.to_s.sub(regex, '').to_sym
677
+ end
678
+ end
679
+ [operator, opts]
680
+ end
681
+
682
+ end
683
+
684
+ # Represents a statement in a policy.
685
+ #
686
+ # @see Policy#allow
687
+ # @see Policy#deny
688
+ class Statement
689
+
690
+ # @return [String] Returns the statement id
691
+ attr_accessor :sid
692
+
693
+ # @return [String] Returns the statement effect, either "Allow" or
694
+ # "Deny"
695
+ attr_accessor :effect
696
+
697
+ # @return [Array] Returns an array of principals.
698
+ attr_accessor :principals
699
+
700
+ # @return [Array] Returns an array of statement actions included
701
+ # by this policy statement.
702
+ attr_accessor :actions
703
+
704
+ # @return [Array] Returns an array of actions excluded by this
705
+ # policy statement.
706
+ attr_accessor :excluded_actions
707
+
708
+ # @return [Array] Returns an array of resources affected by this
709
+ # policy statement.
710
+ attr_accessor :resources
711
+
712
+ # @return [Array] Returns an array of conditions for this policy.
713
+ attr_accessor :conditions
714
+
715
+ # Constructs a new statement.
716
+ #
717
+ # @option opts [String] :sid The statement ID. This is optional; if
718
+ # omitted, a UUID will be generated for the statement.
719
+ # @option opts [String] :effect The statement effect, which must be either
720
+ # "Allow" or "Deny".
721
+ # @see Policy#allow
722
+ # @see Policy#deny
723
+ # @option opts [String or array of strings] :principals The account(s)
724
+ # affected by the statement. These should be AWS account IDs.
725
+ # @option opts :actions The action or actions affected by
726
+ # the statement. These can be symbols or strings. If
727
+ # they are strings, you can use wildcard character "*"
728
+ # to match zero or more characters in the action name.
729
+ # Symbols are expected to match methods of S3::Client.
730
+ # @option opts :excluded_actions Action or actions which are
731
+ # explicitly not affected by this statement. As with
732
+ # +:actions+, these may be symbols or strings.
733
+ # @option opts [String or array of strings] :resources The
734
+ # resource(s) affected by the statement. These can be
735
+ # expressed as ARNs (e.g. +arn:aws:s3:::mybucket/mykey+)
736
+ # or you may omit the +arn:aws:s3:::+ prefix and just give
737
+ # the path as +bucket_name/key+. You may use the wildcard
738
+ # character "*" to match zero or more characters in the
739
+ # resource name.
740
+ # @option opts [ConditionBlock or Hash] :conditions
741
+ # Additional conditions that narrow the effect of the
742
+ # statement. It's typically more convenient to use the
743
+ # ConditionBuilder instance returned from Policy#allow or
744
+ # Policy#deny to add conditions to a statement.
745
+ # @see S3::Client
746
+ def initialize(opts = {})
747
+ self.sid = UUIDTools::UUID.timestamp_create.to_s
748
+ self.conditions = ConditionBlock.new
749
+
750
+ parse_options(opts)
751
+
752
+ yield(self) if block_given?
753
+ end
754
+
755
+ # Convenience method to add to the list of actions affected
756
+ # by this statement.
757
+ def include_actions(*actions)
758
+ self.actions ||= []
759
+ self.actions.push(*actions)
760
+ end
761
+ alias_method :include_action, :include_actions
762
+
763
+ # Convenience method to add to the list of actions
764
+ # explicitly not affected by this statement.
765
+ def exclude_actions(*actions)
766
+ self.excluded_actions ||= []
767
+ self.excluded_actions.push(*actions)
768
+ end
769
+ alias_method :exclude_action, :exclude_actions
770
+
771
+ # @private
772
+ def to_h
773
+ stmt = {
774
+ "Sid" => sid,
775
+ "Effect" => Inflection.class_name(effect.to_s),
776
+ "Principal" => principals_hash,
777
+ "Resource" => resource_arns,
778
+ "Condition" => (conditions.to_h if conditions)
779
+ }
780
+ if !translated_actions || translated_actions.empty?
781
+ stmt["NotAction"] = translated_excluded_actions
782
+ else
783
+ stmt["Action"] = translated_actions
784
+ end
785
+ stmt
786
+ end
787
+
788
+ protected
789
+ def parse_options(options)
790
+ options.each do |name, value|
791
+ name = Inflection.ruby_name(name.to_s)
792
+ name.sub!(/s$/,'')
793
+ send("parse_#{name}_option", value) if
794
+ respond_to?("parse_#{name}_option", true)
795
+ end
796
+ end
797
+
798
+ protected
799
+ def parse_effect_option(value)
800
+ self.effect = value
801
+ end
802
+
803
+ protected
804
+ def parse_sid_option(value)
805
+ self.sid = value
806
+ end
807
+
808
+ protected
809
+ def parse_action_option(value)
810
+ coerce_array_option(:actions, value)
811
+ end
812
+
813
+ protected
814
+ def parse_not_action_option(value)
815
+ coerce_array_option(:excluded_actions, value)
816
+ end
817
+ alias_method :parse_excluded_action_option, :parse_not_action_option
818
+
819
+ protected
820
+ def parse_principal_option(value)
821
+ if value and value.kind_of?(Hash)
822
+ value = value["AWS"] || []
823
+ end
824
+
825
+ coerce_array_option(:principals, value)
826
+ end
827
+
828
+ protected
829
+ def parse_resource_option(value)
830
+ coerce_array_option(:resources, value)
831
+ end
832
+
833
+ protected
834
+ def parse_condition_option(value)
835
+ self.conditions = ConditionBlock.new(value)
836
+ end
837
+
838
+ protected
839
+ def coerce_array_option(attr, value)
840
+ if value.kind_of?(Array)
841
+ send("#{attr}=", value)
842
+ else
843
+ send("#{attr}=", [value])
844
+ end
845
+ end
846
+
847
+ protected
848
+ def principals_hash
849
+ return nil unless principals
850
+ { "AWS" =>
851
+ principals.map do |principal|
852
+ principal == :any ? "*" : principal
853
+ end }
854
+ end
855
+
856
+ protected
857
+ def translate_action(action)
858
+ case action
859
+ when String then action
860
+ when :any then '*'
861
+ when Symbol
862
+
863
+ if self.class == AWS::Policy::Statement
864
+ msg = 'symbolized action names are only accepted by service ' +
865
+ 'specific policies (e.g. AWS::S3::Policy)'
866
+ raise ArgumentError, msg
867
+ end
868
+
869
+ unless self.class::ACTION_MAPPING.has_key?(action)
870
+ raise ArgumentError, "unrecognized action: #{action}"
871
+ end
872
+
873
+ self.class::ACTION_MAPPING[action]
874
+
875
+ end
876
+ end
877
+
878
+ protected
879
+ def translated_actions
880
+ return nil unless actions
881
+ actions.map do |action|
882
+ translate_action(action)
883
+ end
884
+ end
885
+
886
+ protected
887
+ def translated_excluded_actions
888
+ return nil unless excluded_actions
889
+ excluded_actions.map { |a| translate_action(a) }
890
+ end
891
+
892
+ protected
893
+ def resource_arns
894
+ return nil unless resources
895
+ resources.map do |resource|
896
+ case resource
897
+ when :any then "*"
898
+ else resource_arn(resource)
899
+ end
900
+ end
901
+ end
902
+
903
+ protected
904
+ def resource_arn resource
905
+ resource.to_s
906
+ end
907
+
908
+ end
909
+
910
+ end
911
+
912
+ end