module S3Lib class Acl attr_reader :xml, :parent, :url def initialize(parent_or_url) if parent_or_url.respond_to?(:url) @parent = parent_or_url @url = @parent.url.sub(/\/\Z/,'') + '?acl' else @url = parent_or_url.sub(/\/\Z/,'').sub(/\?acl/, '') + '?acl' end end def grants(params = {}) refresh_grants if params[:refresh] @grants || get_grants end def clear_grants @grants = [] set_grants end # permission must be one of :read, :write, :read_acl, :write_acl or :full_control # The grantee Hash should look like this: # {:type => :canonical|:email|:all_s3|:public, # :grantee => canonical_user_id | email_address} # # The :grantee element of the hash is only required (and meaningful) # for :canonical and :email Grants # # Some examples: # Add public read access to an object: # add_grant(:read, :type => :public) # # Give write access to a user with email of 'test@example.com' # add_grant(:write, :type => :email, :grantee => 'test@example.com') # # Give full control to user with canonical ID of 1234567890 # add_grant(:full_control, :type => :canonical, :grantee => 1234567890) # # Note that you still have to PUT your changes to the server. # Do this using set_grants or use the bang version of add_grant # # add_grant(:read, :type => :public) # set_grants() # # add_grant!(:read, :type => :public) def add_grant(permission, grantee) grants.push(S3Lib::Grant.new(permission, grantee)) end # Add a grant and PUT it to the server right away def add_grant!(permission, grantee) add_grant(permission, grantee) set_grants end def remove_grant(grant_num) grants.delete_at(grant_num) refresh_grants end def refresh_grants get_grants end def set_grants Acl.acl_request(:put, @url, :body => to_xml) refresh_grants end def owner get_grants unless @xml @xml.elements['Owner'].elements['ID'].text end def to_xml builder = Builder::XmlMarkup.new(:indent => 2) xml = builder.AccessControlPolicy('xmlns' => 'http://s3.amazonaws.com/doc/2006-03-01/') do builder.Owner do builder.ID(owner) end builder.AccessControlList do grants.each do |grant| builder << grant.to_xml end end end end def inspect grants.collect do |grant| grant.inspect end.join("\n") end private def get_grants response = Acl.acl_request(:get, @url) @xml = REXML::Document.new(response).root @grants = REXML::XPath.match(@xml, '//Grant').collect do |grant| grantee = grant.elements['Grantee'] permission = grant.elements['Permission'].text S3Lib::Grant.new(permission, grantee) end end def self.acl_request(verb, url, options = {}) begin if verb == :put options = {'content-type' => 'text/xml'}.merge(options) # Make sure content-type is set for :put end response = S3Lib.request(verb, url, options) rescue S3Lib::S3ResponseError => error puts "Error of type #{error.amazon_error_type}" case error.amazon_error_type when 'NoSuchBucket': raise S3Lib::BucketNotFoundError.new("The bucket '#{bucket}' does not exist.", error.io, error.s3requester) when 'NotSignedUp': raise S3Lib::NotYourBucketError.new("The bucket '#{bucket}' is owned by somebody else", error.io, error.s3requester) when 'AccessDenied': raise S3Lib::NotYourBucketError.new("The bucket '#{bucket}' is owned by someone else.", error.io, error.s3requester) when 'MalformedACLError': raise S3Lib::MalformedACLError.new("Your ACL was malformed.", error.io, error.s3requester) else # Re-raise the error if it's not one of the above raise end end response end end end