class AWS::Core::Policy::ConditionBlock

Represents the condition block of a policy. In JSON, condition blocks look like this:

{ "StringLike": { "s3:prefix": ["photos/*", "photos.html"] } }

ConditionBlock lets you specify conditions like the above example using the add method, for example:

conditions.add(:like, :s3_prefix, "photos/*", "photos.html")

See the add method documentation for more details about how to specify keys and operators.

This class also provides a convenient way to query a condition block to see what operators, keys, and values it has. For example, consider the following condition block (in JSON):

{
  "StringEquals": {
    "s3:prefix": "photos/index.html"
  },
  "DateEquals": {
    "aws:CurrentTime": ["2010-10-12", "2011-01-02"]
  },
  "NumericEquals": {
    "s3:max-keys": 10
  }
}

You can get access to the condition data using #[], keys, operators, and values – for example:

conditions["DateEquals"]["aws:CurrentTime"].values
  # => ["2010-10-12", "2011-01-02"]

You can also perform more sophisticated queries, like this one:

conditions[:is].each do |equality_conditions|
  equality_conditions.keys.each do |key|
    puts("#{key} may be any of: " +
         equality_conditions[key].values.join(" ")
  end
end

This would print the following lines:

s3:prefix may be any of: photos/index.html
aws:CurrentTime may be any of: 2010-10-12 2011-01-02
s3:max-keys may be any of: 10

Constants

MODIFIERS

@private

Public Class Methods

new(conditions = {}) click to toggle source

@private

# File lib/aws/core/policy.rb, line 298
def initialize(conditions = {})
  # filter makes a copy
  @conditions = filter_conditions(conditions)
end

Public Instance Methods

[](*args) click to toggle source

Filters the conditions described in the block, returning a new ConditionBlock that contains only the matching conditions. Each argument is matched against either the keys or the operators in the block, and you can specify the key or operator in any way that’s valid for the add method. Some examples:

# all conditions using the StringLike operator
conditions["StringLike"]

# all conditions using StringEquals, DateEquals, NumericEquals, or Bool
conditions[:is]

# all conditions on the s3:prefix key
conditions["s3:prefix"]

# all conditions on the aws:CurrentTime key
conditions[:current_time]

Multiple conditions are ANDed together, so the following are equivalent:

conditions[:s3_prefix][:is]
conditions[:is][:s3_prefix]
conditions[:s3_prefix, :is]

@see add @return [ConditionBlock] A new set of conditions filtered by the

given conditions.
# File lib/aws/core/policy.rb, line 410
def [](*args)
  filtered = @conditions
  args.each do |filter|
    type = valid_operator?(filter) ? nil : :key
    filtered = filter_conditions(filtered) do |op, key, value|
      (match, type) = match_triple(filter, type, op, key, value)
      match
    end
  end
  self.class.new(filtered)
end
add(operator, key, *values) click to toggle source

Adds a condition to the block. This method defines a convenient set of abbreviations for operators based on the type of value passed in. For example:

conditions.add(:is, :secure_transport, true)

Maps to:

{ "Bool": { "aws:SecureTransport": true } }

While:

conditions.add(:is, :s3_prefix, "photos/")

Maps to:

{ "StringEquals": { "s3:prefix": "photos/" } }

The following list shows which operators are accepted as symbols and how they are represented in the JSON policy:

  • :is (StringEquals, NumericEquals, DateEquals, or Bool)

  • :like (StringLike)

  • :not_like (StringNotLike)

  • :not (StringNotEquals, NumericNotEquals, or DateNotEquals)

  • :greater_than, :gt (NumericGreaterThan or DateGreaterThan)

  • :greater_than_equals, :gte (NumericGreaterThanEquals or DateGreaterThanEquals)

  • :less_than, :lt (NumericLessThan or DateLessThan)

  • :less_than_equals, :lte (NumericLessThanEquals or DateLessThanEquals)

  • :is_ip_address (IpAddress)

  • :not_ip_address (NotIpAddress)

  • :is_arn (ArnEquals)

  • :not_arn (ArnNotEquals)

  • :is_arn_like (ArnLike)

  • :not_arn_like (ArnNotLike)

@param [Symbol or String] operator The operator used to

compare the key with the value.  See above for valid
values and their interpretations.

@param [Symbol or String] key The key to compare. Symbol

keys are inflected to match AWS conventions.  By
default, the key is assumed to be in the "aws"
namespace, but if you prefix the symbol name with "s3_"
it will be sent in the "s3" namespace.  For example,
+:s3_prefix+ is sent as "s3:prefix" while
+:secure_transport+ is sent as "aws:SecureTransport".
See
http://docs.amazonwebservices.com/AmazonS3/latest/dev/UsingResOpsConditions.html
for a list of the available keys for each action in S3.

@param value The value to compare against.

This can be:
* a String
* a number
* a Date, DateTime, or Time
* a boolean value
This method does not attempt to validate that the values
are valid for the operators or keys they are used with.
# File lib/aws/core/policy.rb, line 364
def add(operator, key, *values)
  if operator.kind_of?(Symbol)
    converted_values = values.map { |v| convert_value(v) }
  else
    converted_values = values
  end
  operator = translate_operator(operator, values.first)
  op = (@conditions[operator] ||= {})
  raise "duplicate #{operator} conditions for #{key}" if op[key]
  op[translate_key(key)] = converted_values
end
keys() click to toggle source

@return [Array] Returns an array of unique keys used in the block.

# File lib/aws/core/policy.rb, line 428
def keys
  @conditions.values.map do |keys|
    keys.keys if keys
  end.compact.flatten.uniq
end
operators() click to toggle source

@return [Array] Returns an array of operators used in this block.

# File lib/aws/core/policy.rb, line 423
def operators
  @conditions.keys
end
to_h() click to toggle source

@private

# File lib/aws/core/policy.rb, line 377
def to_h
  @conditions
end
values() click to toggle source

Returns all values used in the block. Note that the values may not all be from the same condition; for example:

conditions.add(:like, :user_agent, "mozilla", "explorer")
conditions.add(:lt, :s3_max_keys, 12)
conditions.values # => ["mozilla", "explorer", 12]

@return [Array] Returns an array of values used in this condition block.

# File lib/aws/core/policy.rb, line 442
def values
  @conditions.values.map do |keys|
    keys.values
  end.compact.flatten
end

Protected Instance Methods

base_translate(example, base_operator, *modifiers) click to toggle source

@private

# File lib/aws/core/policy.rb, line 635
def base_translate(example, base_operator, *modifiers)
  "#{type_notation(example)}#{base_operator}#{modifiers.join}"
end
convert_value(value) click to toggle source

@private

# File lib/aws/core/policy.rb, line 656
def convert_value(value)
  case value
  when DateTime, Time
    Time.parse(value.to_s).iso8601
  when Date
    value.strftime("%Y-%m-%d")
  else
    value
  end
end
filter_conditions(conditions = @conditions) { |op, key, value| ... } click to toggle source

@private

# File lib/aws/core/policy.rb, line 486
def filter_conditions(conditions = @conditions)
  conditions.inject({}) do |m, (op, keys)|
    m[op] = keys.inject({}) do |m2, (key, value)|
      m2[key] = value if !block_given? or yield(op, key, value)
      m2
    end
    m.delete(op) if m[op].empty?
    m
  end
end
match_key(filter, key, value = nil) click to toggle source

@private

# File lib/aws/core/policy.rb, line 480
def match_key(filter, key, value = nil)
  translate_key(filter) == key
end
match_operator(filter, op, value) click to toggle source

@private

# File lib/aws/core/policy.rb, line 471
def match_operator(filter, op, value)
  # dates are the only values that don't come back as native types in JSON
  # but where we use the type as a cue to the operator translation
  value = Date.today if op =~ %r^Date/
  translate_operator(filter, value) == op
end
match_triple(filter, type, op, key, value) click to toggle source

@private

# File lib/aws/core/policy.rb, line 450
def match_triple(filter, type, op, key, value)
  value = [value].flatten.first
  if type
    target = (type == :operator ? op : key)
    match = send("match_#{type}", filter, target, value)
  else
    if match_operator(filter, op, value)
      match = true
      type = :operator
    elsif match_key(filter, key)
      match = true
      type = :key
    else
      match = false
    end
  end
  [match, type]
end
strip_modifiers(operator) click to toggle source

@private

# File lib/aws/core/policy.rb, line 669
def strip_modifiers(operator)
  opts = {}
  MODIFIERS.each do |(regex, mod)|
    ruby_name = Inflection.ruby_name(mod).to_sym
    opts[ruby_name] = ""
    if operator.to_s =~ regex
      opts[ruby_name] = mod
      operator = operator.to_s.sub(regex, '').to_sym
    end
  end
  [operator, opts]
end
translate_greater_than(example, opts) click to toggle source

@private

# File lib/aws/core/policy.rb, line 586
def translate_greater_than(example, opts)
  base_translate(example, "GreaterThan", opts[:equals])
end
Also aliased as: translate_gt
translate_gt(example, opts) click to toggle source
translate_gte(example, opts) click to toggle source

@private

# File lib/aws/core/policy.rb, line 593
def translate_gte(example, opts)
  translate_greater_than(example, { :equals => "Equals" })
end
translate_is(example, opts) click to toggle source

@private

# File lib/aws/core/policy.rb, line 548
def translate_is(example, opts)
  return "Bool" if type_notation(example) == "Bool"
  base_translate(example, "Equals", opts[:ignore_case])
end
translate_is_arn(example, opts) click to toggle source

@private

# File lib/aws/core/policy.rb, line 611
def translate_is_arn(example, opts)
  "ArnEquals"
end
translate_is_arn_like(example, opts) click to toggle source

@private

# File lib/aws/core/policy.rb, line 623
def translate_is_arn_like(example, opts)
  "ArnLike"
end
translate_is_ip_address(example, opts) click to toggle source

@private

# File lib/aws/core/policy.rb, line 599
def translate_is_ip_address(example, opts)
  "IpAddress"
end
translate_key(key) click to toggle source

@private

# File lib/aws/core/policy.rb, line 499
def translate_key(key)
  if key.kind_of?(Symbol)
    if key.to_s =~ %r^s3_(.*)$/
      s3_name = $1
      if s3_name == "version_id" or
          s3_name == "location_constraint"
        s3_name = Inflection.class_name(s3_name)
      else
        s3_name.tr!('_', '-')
      end
      "s3:#{s3_name}"
    else
      "aws:#{Inflection.class_name(key.to_s)}"
    end
  else
    key
  end
end
translate_less_than(example, opts) click to toggle source

@private

# File lib/aws/core/policy.rb, line 573
def translate_less_than(example, opts)
  base_translate(example, "LessThan", opts[:equals])
end
Also aliased as: translate_lt
translate_like(example, opts) click to toggle source

@private

# File lib/aws/core/policy.rb, line 561
def translate_like(example, opts)
  base_translate(example, "Like")
end
translate_lt(example, opts) click to toggle source
Alias for: translate_less_than
translate_lte(example, opts) click to toggle source

@private

# File lib/aws/core/policy.rb, line 580
def translate_lte(example, opts)
  translate_less_than(example, { :equals => "Equals" })
end
translate_not(example, opts) click to toggle source

@private

# File lib/aws/core/policy.rb, line 555
def translate_not(example, opts)
  base_translate(example, "NotEquals", opts[:ignore_case])
end
translate_not_arn(example, opts) click to toggle source

@private

# File lib/aws/core/policy.rb, line 617
def translate_not_arn(example, opts)
  "ArnNotEquals"
end
translate_not_arn_like(example, opts) click to toggle source

@private

# File lib/aws/core/policy.rb, line 629
def translate_not_arn_like(example, opts)
  "ArnNotLike"
end
translate_not_ip_address(example, opts) click to toggle source

@private

# File lib/aws/core/policy.rb, line 605
def translate_not_ip_address(example, opts)
  "NotIpAddress"
end
translate_not_like(example, opts) click to toggle source

@private

# File lib/aws/core/policy.rb, line 567
def translate_not_like(example, opts)
  base_translate(example, "NotLike")
end
translate_operator(operator, example_value) click to toggle source

@private

# File lib/aws/core/policy.rb, line 535
def translate_operator(operator, example_value)
  return operator if operator.kind_of?(String)
  
  original_operator = operator
  (operator, opts) = strip_modifiers(operator)
  
  raise ArgumentError.new("unrecognized operator #{original_operator}") unless
    respond_to?("translate_#{operator}", true)
  send("translate_#{operator}", example_value, opts)
end
type_notation(example) click to toggle source

@private

# File lib/aws/core/policy.rb, line 641
def type_notation(example)
  case example
  when String
    "String"
  when Numeric
    "Numeric"
  when Time, Date
    "Date"
  when true, false
    "Bool"
  end
end
valid_operator?(operator) click to toggle source

@private

# File lib/aws/core/policy.rb, line 526
def valid_operator?(operator)
  translate_operator(operator, "")
  true
rescue ArgumentError => e
  false
end