1
0
Fork 0
mirror of https://github.com/fog/fog.git synced 2022-11-09 13:51:43 -05:00

Add grant, revoke and list methods for cross tenant object acls implementation.

This commit is contained in:
Rupak Ganguly 2012-10-16 21:48:50 -04:00
parent 0ce276f4f7
commit 13509fced4
3 changed files with 144 additions and 39 deletions

View file

@ -58,7 +58,10 @@ module Fog
end end
# set the acl on the directory based on the headers # set the acl on the directory based on the headers
if !(read_header.nil? && write_header.nil?) if !(read_header.nil? && write_header.nil?)
directory.acl = connection.header_to_acl(read_header, write_header) read_acl, write_acl = connection.header_to_perm_acl(read_header, write_header)
# do not want to expose the read_acl and write_acl as writable attributes
directory.instance_variable_set(:@read_acl, read_acl)
directory.instance_variable_set(:@write_acl, write_acl)
end end
directory.files.merge_attributes(options) directory.files.merge_attributes(options)
directory.files.instance_variable_set(:@loaded, true) directory.files.instance_variable_set(:@loaded, true)

View file

@ -12,15 +12,70 @@ module Fog
attribute :bytes, :aliases => 'X-Container-Bytes-Used' attribute :bytes, :aliases => 'X-Container-Bytes-Used'
attribute :count, :aliases => 'X-Container-Object-Count' attribute :count, :aliases => 'X-Container-Object-Count'
def acl=(new_acl) def initialize(attributes = {})
if new_acl.nil? @read_acl = []
new_acl = "private" @write_acl = []
super
end
def read_acl
@read_acl
end
def write_acl
@write_acl
end
def can_read?(user)
return false if @read_acl.nil?
list_users_with_read.include?(user)
end
def can_write?(user)
return false if @write_acl.nil?
list_users_with_write.include?(user)
end
def can_read_write?(user)
can_read?(user) && can_write?(user)
end
def list_users_with_read
users = []
users = @read_acl.map {|acl| acl.split(':')[1]} unless @read_acl.nil?
return users
end
def list_users_with_write
users = []
users = @write_acl.map {|acl| acl.split(':')[1]} unless @write_acl.nil?
return users
end
def grant(perm, users=[])
r_acl, w_acl = connection.perm_to_acl(perm, users)
unless r_acl.nil?
@read_acl = @read_acl + r_acl
@read_acl.uniq!
end end
valid_acls = ['private', 'public-read', 'public-write', 'public-read-write'] unless w_acl.nil?
unless valid_acls.include?(new_acl) @write_acl = @write_acl + w_acl
raise ArgumentError.new("acl must be one of [#{valid_acls.join(', ')}]") @write_acl.uniq!
end end
@acl = new_acl true
end
def revoke(perm, users=[])
r_acl, w_acl = connection.perm_to_acl(perm, users)
unless r_acl.nil?
@read_acl = @read_acl - r_acl
@read_acl.uniq!
end
unless w_acl.nil?
@write_acl = @write_acl - w_acl
@write_acl.uniq!
end
true
end end
def destroy def destroy
@ -50,18 +105,20 @@ module Fog
def public=(new_public) def public=(new_public)
if new_public if new_public
@acl = 'public-read' self.grant("pr")
else else
@acl = 'private' self.revoke("pr")
end end
@public = new_public @public = new_public
end end
def public? def public?
if @acl.nil? if @read_acl.empty?
false false
elsif @read_acl.include?(".r:*")
true
else else
@acl == 'public-read' false
end end
end end
@ -70,7 +127,7 @@ module Fog
@public_url ||= begin @public_url ||= begin
begin response = connection.head_container(key) begin response = connection.head_container(key)
# escape the key to cover for special char. in container names # escape the key to cover for special char. in container names
url = "#{connection.url}/#{Fog::HP.escape(key)}" url = connection.public_url(key)
rescue Fog::Storage::HP::NotFound => err rescue Fog::Storage::HP::NotFound => err
nil nil
end end
@ -135,9 +192,8 @@ module Fog
def save def save
requires :key requires :key
options = {} options = {}
if @acl # write out the acls into the headers before save
options.merge!(connection.acl_to_header(@acl)) options.merge!(connection.perm_acl_to_header(@read_acl, @write_acl))
end
connection.put_container(key, options) connection.put_container(key, options)
# Added an extra check to see if CDN is enabled for the container # Added an extra check to see if CDN is enabled for the container
if (!connection.cdn.nil? && connection.cdn.enabled?) if (!connection.cdn.nil? && connection.cdn.enabled?)

View file

@ -53,34 +53,80 @@ module Fog
"#{@scheme}://#{@host}:#{@port}#{@path}" "#{@scheme}://#{@host}:#{@port}#{@path}"
end end
def acl_to_header(acl) def public_url(container=nil, object=nil)
public_url = nil
unless container.nil?
if object.nil?
# return container public url
public_url = "#{url}/#{Fog::HP.escape(container)}"
else
# return object public url
public_url = "#{url}/#{Fog::HP.escape(container)}/#{Fog::HP.escape(object)}"
end
end
public_url
end
def perm_to_acl(perm, users=[])
read_perm_acl = []
write_perm_acl = []
valid_public_perms = ['pr', 'pw', 'prw']
valid_account_perms = ['r', 'w', 'rw']
valid_perms = valid_public_perms + valid_account_perms
unless valid_perms.include?(perm)
raise ArgumentError.new("permission must be one of [#{valid_perms.join(', ')}]")
end
# tackle the public access differently
if valid_public_perms.include?(perm)
case perm
when "pr"
read_perm_acl = [".r:*",".rlistings"]
when "pw"
write_perm_acl = ["*"]
when "prw"
read_perm_acl = [".r:*",".rlistings"]
write_perm_acl = ["*"]
end
elsif valid_account_perms.include?(perm)
# tackle the user access differently
unless (users.nil? || users.empty?)
# return the correct acls
tenant_id = "*" # this might change later
acl_array = users.map { |u| "#{tenant_id}:#{u}" }
#acl_string = acl_array.join(',')
case perm
when "r"
read_perm_acl = acl_array
when "w"
write_perm_acl = acl_array
when "rw"
read_perm_acl = acl_array
write_perm_acl = acl_array
end
end
end
return read_perm_acl, write_perm_acl
end
def perm_acl_to_header(read_perm_acl, write_perm_acl)
header = {} header = {}
case acl if read_perm_acl.nil? && write_perm_acl.nil?
when "private" header = {'X-Container-Read' => "", 'X-Container-Write' => ""}
header['X-Container-Read'] = "" elsif !read_perm_acl.nil? && write_perm_acl.nil?
header['X-Container-Write'] = "" header = {'X-Container-Read' => "#{read_perm_acl.join(',')}", 'X-Container-Write' => ""}
when "public-read" elsif read_perm_acl.nil? && !write_perm_acl.nil?
header['X-Container-Read'] = ".r:*,.rlistings" header = {'X-Container-Read' => "", 'X-Container-Write' => "#{write_perm_acl.join(',')}"}
when "public-write" elsif !read_perm_acl.nil? && !write_perm_acl.nil?
header['X-Container-Write'] = "*" header = {'X-Container-Read' => "#{read_perm_acl.join(',')}", 'X-Container-Write' => "#{write_perm_acl.join(',')}"}
when "public-read-write"
header['X-Container-Read'] = ".r:*,.rlistings"
header['X-Container-Write'] = "*"
end end
header header
end end
def header_to_acl(read_header=nil, write_header=nil) def header_to_perm_acl(read_header=nil, write_header=nil)
acl = nil read_h, write_h = nil
if read_header.nil? && write_header.nil? read_h = read_header.split(',') unless read_header.nil?
acl = nil write_h = write_header.split(',') unless write_header.nil?
elsif !read_header.nil? && read_header.include?(".r:*") && write_header.nil? return read_h, write_h
acl = "public-read"
elsif !write_header.nil? && write_header.include?("*") && read_header.nil?
acl = "public-write"
elsif !read_header.nil? && read_header.include?(".r:*") && !write_header.nil? && write_header.include?("*")
acl = "public-read-write"
end
end end
def generate_object_temp_url(container, object, expires_secs, method) def generate_object_temp_url(container, object, expires_secs, method)