__all__ = ["ACLRule"]
def _max(a, b):
"""Function to do most-permissive addition of two bools
True + True = True
True + False = True
False + True = True
False + False = False
True + None = True
None + True = True
False + None = False
None + False = False
None + None = None
"""
if a is None:
return b
elif b is None:
return a
elif a is True:
return True
else:
return b
def _sub(a, b):
"""Function to do subtraction of two bools
True - True = False
True - False = True
False - True = False
False - False = False
True - None = True
None - True = False
False - None = False
None - False = None
None - None = None
"""
if b is True:
return False
else:
return a
def _min(a, b):
"""Function to do least-permission addition of two bools
True * True = True
True * False = False
False * True = False
False * False = False
True * None = True
None * True = True
False * None = False
None * False = False
None - None = None
"""
if a is None:
return b
elif b is None:
return a
elif a is False:
return False
else:
return b
[docs]class ACLRule:
"""This class holds the access control list (ACL) rule for
a particular user accessing a particular resource
"""
def __init__(self, is_owner=None, is_readable=None,
is_writeable=None, is_executable=None):
"""Construct a default rule. By default this rule has
fully-inherit permissions (nothing is set either way)
"""
if is_owner is None:
self._is_owner = None
elif is_owner:
self._is_owner = True
else:
self._is_owner = False
if is_readable is None:
self._is_readable = None
elif is_readable:
self._is_readable = True
else:
self._is_readable = False
if is_writeable is None:
self._is_writeable = None
elif is_writeable:
self._is_writeable = True
else:
self._is_writeable = False
if is_executable is None:
self._is_executable = None
elif is_executable:
self._is_executable = True
else:
self._is_executable = False
def __str__(self):
s = []
if self.is_owner():
s.append("owner")
elif self.inherits_owner():
s.append("inherits_owner")
if self.is_writeable():
s.append("writeable")
elif self.inherits_writeable():
s.append("inherits_writeable")
if self.is_readable():
s.append("readable")
elif self.inherits_readable():
s.append("inherits_readable")
if self.is_executable():
s.append("executable")
elif self.inherits_executable():
s.append("inherits_executable")
if len(s) == 0:
return "ACLRule::denied"
else:
return "ACLRule(%s)" % ", ".join(s)
def __eq__(self, other):
if isinstance(other, self.__class__):
return self.__dict__ == other.__dict__
else:
return False
def __add__(self, other):
"""Add two rules together - this will combine the parts
additively, i.e. the most-permissive options are set
in the return value
"""
if not isinstance(other, ACLRule):
raise TypeError(
"You can only combine together pairs of ACLRules")
return ACLRule(
is_owner=_max(self._is_owner, other._is_owner),
is_writeable=_max(self._is_writeable, other._is_writeable),
is_readable=_max(self._is_readable, other._is_readable),
is_executable=_max(self._is_executable, other._is_executable))
def __sub__(self, other):
"""Subtract 'other' from these rules - if 'other' is False
the this is set to False
"""
if not isinstance(other, ACLRule):
raise TypeError(
"You can only combine together pairs of ACLRules")
return ACLRule(
is_owner=_sub(self._is_owner, other._is_owner),
is_writeable=_sub(self._is_writeable, other._is_writeable),
is_readable=_sub(self._is_readable, other._is_readable),
is_executable=_sub(self._is_executable, other._is_executable))
def __mul__(self, other):
"""Combine two rules together - this will combine
the parts subtractively, i.e. the least permissive options
are set in the return value
"""
if not isinstance(other, ACLRule):
raise TypeError(
"You can only combine together pairs of ACLRules")
return ACLRule(
is_owner=_min(self._is_owner, other._is_owner),
is_writeable=_min(self._is_writeable, other._is_writeable),
is_readable=_min(self._is_readable, other._is_readable),
is_executable=_min(self._is_executable, other._is_executable))
[docs] @staticmethod
def owner():
"""Return the ACLRule of an owner"""
return ACLRule(is_owner=True, is_readable=True,
is_writeable=True, is_executable=True)
[docs] @staticmethod
def executer():
"""Return the ACLRule of an executer"""
return ACLRule(is_owner=False, is_executable=True,
is_writeable=True, is_readable=True)
[docs] @staticmethod
def writer():
"""Return the ACLRule of a writer"""
return ACLRule(is_owner=False, is_readable=True,
is_writeable=True, is_executable=False)
[docs] @staticmethod
def reader():
"""Return the ACLRule of a reader"""
return ACLRule(is_owner=False, is_readable=True,
is_writeable=False, is_executable=False)
[docs] @staticmethod
def denied():
"""Return a "denied" (no-access at all) permission rule"""
return ACLRule(is_owner=False, is_readable=False,
is_writeable=False, is_executable=False)
[docs] @staticmethod
def null():
"""Return a null (inherit all permissions) rule"""
return ACLRule(is_owner=None, is_readable=None,
is_writeable=None, is_executable=None)
[docs] @staticmethod
def inherit():
"""Return the ACL rule that means 'inherit permissions from parent'"""
return ACLRule(is_owner=None, is_readable=None,
is_writeable=None, is_executable=None)
[docs] def is_owner(self):
"""Return whether or not the user is the owner of this resource"""
return self._is_owner
[docs] def is_readable(self):
"""Return whether or not the user can read this resource"""
return self._is_readable
[docs] def is_writeable(self):
"""Return whether or not the user can write to this resource"""
return self._is_writeable
[docs] def is_executable(self):
"""Return whether or not the user can execute this resource"""
return self._is_executable
[docs] def inherits_owner(self):
"""Return whether or not this inherits the owner status
from upstream
"""
return self._is_owner is None
[docs] def inherits_readable(self):
"""Return whether or not this inherits the reader status
from upstream
"""
return self._is_readable is None
[docs] def inherits_writeable(self):
"""Return whether or not this inherits the writeable status
from upstream
"""
return self._is_writeable is None
[docs] def inherits_executable(self):
"""Return whether or not this inherits the executable status
from upstream
"""
return self._is_executable is None
[docs] def inherits_all(self):
"""Return whether or not this rule inherits all permissions"""
return (self._is_owner is None) and \
(self._is_readable is None) and \
(self._is_writeable is None) and \
(self._is_executable is None)
[docs] def is_fully_resolved(self):
"""Return whether or not this rule is fully resolved"""
return (self._is_owner is not None) and \
(self._is_readable is not None) and \
(self._is_writeable is not None) and \
(self._is_executable is not None)
[docs] def denied_all(self):
"""Return whether or not this rule shows that everything is
denied
"""
return (self._is_owner is False) and \
(self._is_readable is False) and \
(self._is_writeable is False) and \
(self._is_executable is False)
def _force_resolve(self, unresolved=False):
"""This returns a fully resolved ACL, where anything that
is not resolved is set equal to 'unresolved'
"""
if unresolved:
unresolved = True
else:
unresolved = False
is_owner = self._is_owner
is_readable = self._is_readable
is_writeable = self._is_writeable
is_executable = self._is_executable
if is_owner is None:
is_owner = unresolved
if is_readable is None:
is_readable = unresolved
if is_executable is None:
is_executable = unresolved
if is_writeable is None:
is_writeable = unresolved
return ACLRule(is_owner=is_owner, is_writeable=is_writeable,
is_readable=is_readable, is_executable=is_executable)
[docs] def resolve(self, must_resolve=True, identifiers=None,
upstream=None, unresolved=False):
"""Resolve these rules based on the information supplied
in 'identifiers'. Notably, if any of our rules are 'inherit',
the this will look into 'upstream' to
inherit the rule. If 'must_resolve' is true, then
this function must always return a fully-resolved ACLRule
(in which any unresolved parts are set equal to 'unresolved')
"""
if self.is_fully_resolved():
return self
if upstream is None:
if must_resolve:
return self._force_resolve(unresolved=unresolved)
else:
return self
from Acquire.Identity import ACLRules as _ACLRules
if isinstance(upstream, _ACLRules):
upstream = upstream.resolve(must_resolve=False,
identifiers=identifiers)
if must_resolve and (not upstream.is_fully_resolved()):
upstream = upstream._force_resolve(unresolved=unresolved)
is_owner = self._is_owner
is_readable = self._is_readable
is_writeable = self._is_writeable
is_executable = self._is_executable
if is_owner is None:
is_owner = upstream._is_owner
if is_readable is None:
is_readable = upstream._is_readable
if is_writeable is None:
is_writeable = upstream._is_writeable
if is_executable is None:
is_executable = upstream._is_executable
result = ACLRule(is_owner=is_owner, is_writeable=is_writeable,
is_readable=is_readable, is_executable=is_executable)
if must_resolve:
result = result._force_resolve(unresolved=unresolved)
return result
[docs] def set_owner(self, is_owner=True):
"""Set the user as an owner of the bucket"""
if is_owner:
self._is_owner = True
else:
self._is_owner = False
[docs] def set_readable(self, is_readable=True):
"""Set the readable rule to 'is_readable'"""
if is_readable:
self._is_readable = True
else:
self._is_readable = False
[docs] def set_writeable(self, is_writeable=True):
"""Set the writeable rule to 'is_writeable'"""
if is_writeable:
self._is_writeable = True
else:
self._is_writeable = False
[docs] def set_inherits_owner(self):
"""Set that this ACL inherits ownership from its parent"""
self._is_owner = None
[docs] def set_inherits_readable(self):
"""Set that this ACL inherits readable from its parent"""
self._is_readable = None
[docs] def set_inherits_writeable(self):
"""Set that this ACL inherits writeable from its parent"""
self._is_writeable = None
[docs] def set_readable_writeable(self, is_readable_writeable=True):
"""Set both the readable and writeable rules to
'is_readable_writeable'
"""
if is_readable_writeable:
self._is_readable = True
self._is_writeable = True
else:
self._is_readable = False
self._is_writeable = False
[docs] def to_data(self):
"""Return this object converted to a json-serialisable object"""
if self.inherits_all():
return "inherits"
elif self == ACLRule.owner():
return "owner"
elif self == ACLRule.reader():
return "reader"
elif self == ACLRule.writer():
return "writer"
elif self == ACLRule.denied():
return "denied"
elif self == ACLRule.executer():
return "executer"
else:
data = {}
data["is_owner"] = self._is_owner
data["is_readable"] = self._is_readable
data["is_writeable"] = self._is_writeable
data["is_executable"] = self._is_executable
return data
[docs] @staticmethod
def from_data(data):
"""Return this object constructed from the passed json-deserialised
dictionary
"""
if data is None:
return None
if isinstance(data, str):
if data == "inherits":
return ACLRule.inherit()
elif data == "owner":
return ACLRule.owner()
elif data == "reader":
return ACLRule.reader()
elif data == "writer":
return ACLRule.writer()
elif data == "executer":
return ACLRule.executer()
elif data == "denied":
return ACLRule.denied()
is_owner = None
is_readable = None
is_writeable = None
if "is_owner" in data:
if data["is_owner"]:
is_owner = True
elif data["is_owner"] is not None:
is_owner = False
if "is_readable" in data:
if data["is_readable"]:
is_readable = True
elif data["is_readable"] is not None:
is_readable = False
if "is_writeable" in data:
if data["is_writeable"]:
is_writeable = True
elif data["is_writeable"] is not None:
is_writeable = False
if "is_executable" in data:
if data["is_executable"]:
is_executable = True
elif data["is_executable"] is not None:
is_executable = False
return ACLRule(is_owner=is_owner,
is_writeable=is_writeable,
is_readable=is_readable,
is_executable=is_executable)