-
Notifications
You must be signed in to change notification settings - Fork 1
Home
nickjer edited this page Jun 30, 2016
·
50 revisions
Ideas...
# facl.rb
class FACL
attr_reader :acls
def initialize(acls:)
@acls = acls
end
# @example Check if user 'bob' has 'r' access
# my_facl.allow?(principle: User.new('bob'), permission: :r)
# #=> true
def allow?(principle:, permission:)
acls.each do |acl|
if acl.match(principle: principle, permission: permission)
# Check if its an allow or deny acl (may not be both)
return true if acl.allow?
return false if acl.deny?
end
end
return false # default deny
end
end
# facl_entry.rb
class FACLEntry
def initialize(principle:, permissions:)
@principle = principle.to_s
@permissions = permissions.map(&:to_sym)
end
def allow?
true
end
def deny?
!allow?
end
def match(principle:, permission:)
self.principle == principle && self.permissions.include?(permission.to_sym)
end
def ==(other)
[self.class, principle, permissions.sort] == [other.class, other.principle, other.permissions.sort]
end
alias_method :eql, :==
def hash
[self.class, principle, permissions.sort].hash
end
end
# facls/nfs4.rb
module FACLs
class NFS4FACL < FACL
def self.get_facl(file)
# Handle errors here (e.g., file doesn't exist, ...)
parse `nfs4_getfacl "#{file}"`
end
def self.add_facl(file, entry)
`nfs4_setfacl -a "#{entry}" "#{file}"`
end
def self.rem_facl(file, entry)
`nfs4_setfacl -x "#{entry}" "#{file}"`
end
def self.set_facl(file, facl)
`nfs4_setfacl -s "#{facl}" "#{file}"`
end
def self.parse(acl_list)
acls = []
acl_list.split("\n").grep(/^[#{NFS4Entry::VALID_TYPE.join}]:/) do |entry|
acls << NFS4Entry.parse entry
end
new(acls: acls)
end
def to_s(sep = ", ")
@acls.join(sep)
end
end
class NFS4FACLEntry < FACLEntry
VALID_TYPE = %i[ A U D L ]
VALID_FLAG = %i[ f d p i S F g ]
VALID_PERMISSION = %i[ r w a x d D t T n N c C o y ]
DEFAULT_DOMAIN = "osc.edu"
attr_reader :type, :flags, :principle, :permissions, :domain
def self.parse(acl_string)
# Create new NFS4Entry from string
type, flags, principle, permissions = acl_string.strip.split(":")
flags = flags.chars
permissions = permissions.chars
principle, domain = principle.split("@")
new(type: type, flags: flags, principle: principle, domain: domain, permissions: permissions)
end
def initialize(type:, flags:, domain: nil, **kwargs)
super(kwargs)
@type = type.to_sym
@flags = flags.map(&:to_sym)
@domain = domain.to_s
# Check for invalid values!
end
def allow?
type == :A
end
def deny?
type == :D
end
def group_acl?
flags.include? :g
end
def match(principle:, permission:)
# FIXME: USER@, GROUP@, OTHER@
if principle.is_a?(User) && group_acl?
principle.groups.include?(self.principle) && self.permissions.include?(permission.to_sym)
elsif principle.is_a?(User) || (principle.is_a?(Group) && group_acl?)
self.principle == principle && self.permissions.include?(permission.to_sym)
else
false
end
end
def to_s
"#{type}:#{flags.join}:#{principle}@#{domain || DEFAULT_DOMAIN}:#{permissions.join}"
end
def ==(other)
[self.class, type, flags.sort, principle, domain, permissions.sort] == [other.class, other.type, other.flags.sort, other.principle, other.domain, other.permissions.sort]
end
def hash
[self.class, type, flags.sort, principle, domain, permissions.sort].hash
end
end
end
facl = OodSupport::FACLs::NFS4FACL.get_facl("/path/to/file")
# Check if user "jnicklas" has read permissions to file
user = OodSupport::User.new "jnicklas"
facl.allow?(principle: user, permission: :r)
#=> false
# Add "rx" permissions for user "jnicklas" to file
entry = OodSupport::FACLs::NFS4FACLEntry.new(type: :A, flags: [], principle: "jnicklas", domain: "osc.edu", permissions: [:r, :x])
OodSupport::FACLs::NFS4FACL.add_facl("/path/to/file", entry)
facl = OodSupport::FACLs::NFS4FACL.get_facl("/path/to/file")
facl.allow?(principle: user, permission: :r)
#=> true