module Aws
# There are 2 ways to set permissions for a bucket or key (called a +thing+ below):
#
# 1 . Use +perms+ param to set 'Canned Access Policies' when calling the bucket.create,
# bucket.put and key.put methods.
# The +perms+ param can take these values: 'private', 'public-read', 'public-read-write' and
# 'authenticated-read'.
# (see http://docs.amazonwebservices.com/AmazonS3/2006-03-01/RESTAccessPolicy.html).
#
# bucket = s3.bucket('bucket_for_kd_test_13', true, 'public-read')
# key.put('Woohoo!','public-read-write' )
#
# 2 . Use Grantee instances (the permission is a +String+ or an +Array+ of: 'READ', 'WRITE',
# 'READ_ACP', 'WRITE_ACP', 'FULL_CONTROL'):
#
# bucket = s3.bucket('my_awesome_bucket', true)
# grantee1 = Aws::S3::Grantee.new(bucket, 'a123b...223c', FULL_CONTROL, :apply)
# grantee2 = Aws::S3::Grantee.new(bucket, 'xy3v3...5fhp', [READ, WRITE], :apply)
#
# There is only one way to get and to remove permission (via Grantee instances):
#
# grantees = bucket.grantees # a list of Grantees that have any access for this bucket
# grantee1 = Aws::S3::Grantee.new(bucket, 'a123b...223c')
# grantee1.perms #=> returns a list of perms for this grantee to that bucket
# ...
# grantee1.drop # remove all perms for this grantee
# grantee2.revoke('WRITE') # revoke write access only
#
class S3::Grantee
# A bucket or a key the grantee has an access to.
attr_reader :thing
# Grantee Amazon id.
attr_reader :id
# Grantee display name.
attr_reader :name
# Array of permissions.
attr_accessor :perms
# Retrieve Owner information and a list of Grantee instances that have
# a access to this thing (bucket or key).
#
# bucket = s3.bucket('my_awesome_bucket', true, 'public-read')
# ...
# Aws::S3::Grantee.owner_and_grantees(bucket) #=> [owner, grantees]
#
def self.owner_and_grantees(thing)
if thing.is_a?(Bucket)
bucket, key = thing, ''
else
bucket, key = thing.bucket, thing
end
hash = bucket.s3.interface.get_acl_parse(bucket.to_s, key.to_s)
owner = Owner.new(hash[:owner][:id], hash[:owner][:display_name])
grantees = []
hash[:grantees].each do |id, params|
grantees << new(thing, id, params[:permissions], nil, params[:display_name])
end
[owner, grantees]
end
# Retrieves a list of Grantees instances that have an access to this thing(bucket or key).
#
# bucket = s3.bucket('my_awesome_bucket', true, 'public-read')
# ...
# Aws::S3::Grantee.grantees(bucket) #=> grantees
#
def self.grantees(thing)
owner_and_grantees(thing)[1]
end
def self.put_acl(thing, owner, grantees) #:nodoc:
if thing.is_a?(Bucket)
bucket, key = thing, ''
else
bucket, key = thing.bucket, thing
end
body = "" +
"" +
"#{owner.id}" +
"#{owner.name}" +
"" +
"" +
grantees.map { |grantee| grantee.to_xml }.join +
"" +
""
bucket.s3.interface.put_acl(bucket.to_s, key.to_s, body)
end
# Create a new Grantee instance.
# Grantee +id+ must exist on S3. If +action+ == :refresh, then retrieve
# permissions from S3 and update @perms. If +action+ == :apply, then apply
# perms to +thing+ at S3. If +action+ == :apply_and_refresh then it performs.
# both the actions. This is used for the new grantees that had no perms to
# this thing before. The default action is :refresh.
#
# bucket = s3.bucket('my_awesome_bucket', true, 'public-read')
# grantee1 = Aws::S3::Grantee.new(bucket, 'a123b...223c', FULL_CONTROL)
# ...
# grantee2 = Aws::S3::Grantee.new(bucket, 'abcde...asdf', [FULL_CONTROL, READ], :apply)
# grantee3 = Aws::S3::Grantee.new(bucket, 'aaaaa...aaaa', 'READ', :apply_and_refresh)
#
def initialize(thing, id, perms=[], action=:refresh, name=nil)
@thing = thing
@id = id
@name = name
@perms = perms.to_a
case action
when :apply then
apply
when :refresh then
refresh
when :apply_and_refresh then
apply; refresh
end
end
# Return +true+ if the grantee has any permissions to the thing.
def exists?
self.class.grantees(@thing).each do |grantee|
return true if @id == grantee.id
end
false
end
# Return Grantee type (+String+): "Group" or "CanonicalUser".
def type
@id[/^http:/] ? "Group" : "CanonicalUser"
end
# Return a name or an id.
def to_s
@name || @id
end
# Add permissions for grantee.
# Permissions: 'READ', 'WRITE', 'READ_ACP', 'WRITE_ACP', 'FULL_CONTROL'.
# See http://docs.amazonwebservices.com/AmazonS3/2006-03-01/UsingPermissions.html .
# Returns +true+.
#
# grantee.grant('FULL_CONTROL') #=> true
# grantee.grant('FULL_CONTROL','WRITE','READ') #=> true
# grantee.grant(['WRITE_ACP','READ','READ_ACP']) #=> true
#
def grant(*permissions)
permissions.flatten!
old_perms = @perms.dup
@perms += permissions
@perms.uniq!
return true if @perms == old_perms
apply
end
# Revoke permissions for grantee.
# Permissions: 'READ', 'WRITE', 'READ_ACP', 'WRITE_ACP', 'FULL_CONTROL'
# See http://docs.amazonwebservices.com/AmazonS3/2006-03-01/UsingPermissions.html .
# Default value is 'FULL_CONTROL'.
# Returns +true+.
#
# grantee.revoke('READ') #=> true
# grantee.revoke('FULL_CONTROL','WRITE') #=> true
# grantee.revoke(['READ_ACP','WRITE_ACP']) #=> true
#
def revoke(*permissions)
permissions.flatten!
old_perms = @perms.dup
@perms -= permissions
@perms.uniq!
return true if @perms == old_perms
apply
end
# Revoke all permissions for this grantee.
# Returns +true+.
#
# grantee.drop #=> true
#
def drop
@perms = []
apply
end
# Refresh grantee perms for its +thing+.
# Returns +true+ if the grantee has perms for this +thing+ or
# +false+ otherwise, and updates @perms value as a side-effect.
#
# grantee.grant('FULL_CONTROL') #=> true
# grantee.refresh #=> true
# grantee.drop #=> true
# grantee.refresh #=> false
#
def refresh
@perms = []
self.class.grantees(@thing).each do |grantee|
if @id == grantee.id
@name = grantee.name
@perms = grantee.perms
return true
end
end
false
end
# Apply current grantee @perms to +thing+. This method is called internally by the +grant+
# and +revoke+ methods. In normal use this method should not
# be called directly.
#
# grantee.perms = ['FULL_CONTROL']
# grantee.apply #=> true
#
def apply
@perms.uniq!
owner, grantees = self.class.owner_and_grantees(@thing)
# walk through all the grantees and replace the data for the current one and ...
grantees.map! { |grantee| grantee.id == @id ? self : grantee }
# ... if this grantee is not known - add this bad boy to a list
grantees << self unless grantees.include?(self)
# set permissions
self.class.put_acl(@thing, owner, grantees)
end
def to_xml # :nodoc:
id_str = @id[/^http/] ? "#{@id}" : "#{@id}"
grants = ''
@perms.each do |perm|
grants << "" +
"#{id_str}" +
"#{perm}" +
""
end
grants
end
end
end