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:
parent
0ce276f4f7
commit
13509fced4
3 changed files with 144 additions and 39 deletions
|
@ -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)
|
||||||
|
|
|
@ -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?)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Add table
Reference in a new issue