The acl is an object that can be queried to determine if a particular role has permission to access a resource. Each permission is also associated with a 'privilege'. For example, a manager may have both the 'read' and 'write' privileges for the weekly schedule, but an employee only has the 'read' privilege.
import acl
# Each user name should be associated with a role.
role = get_role(username)
# Query the acl to see if a role has access to a resource.
# params: role name, resource, privilege
acl = acl.Acl()
if not acl.check_access(role, 'time_card', 'write'):
# User doesn't have access to this resource!!
pass
The Acl class supports role inheritance. If the 'manager' role inherits the 'employee' role, then managers will have all of the same permissions as employees.
# Build acl list
acl = acl.Acl()
employee = acl.Role('employee')
resource = acl.Resource('time_card')
resource.set_privilege('write')
employee.set_resource(resource)
acl.set_role(employee)
manager = acl.Role('manager')
manager.set_parent(employee)
resource = acl.Resource('time_card')
resource.set_privilege('approve')
manager.set_resource(resource)
acl.set_role(manager)
if acl.check_access('manager', 'time_card', 'write'):
# YES!
pass
if acl.check_acces('manager', 'time_card', 'approve'):
# YES!
pass
if acl.check_access('employee', 'time_card', 'write'):
# YES !
pass
if acl.check_access('employess', 'time_card', 'approve');
# NO!
pass
I'm normally not a very big fan of XML, but in this particular case it is a good format to use if you prefer to store your acl in a configuration file. The Acl object's 'build_acl' method populates the object from a XML file with the following format:
<?xml version="1.0"?>
<!--
- This file configures the roles (user groups)
- and permissions for accessing the system.
-->
<config>
<!--
- Setup roles here.
- Use the 'inheritFrom' tag to
- inherit permissions from another role.
-->
<roleSet>
<role>
<name>customer</name>
</role>
<role>
<name>employee</name>
<inheritFrom>customer</inheritFrom>
</role>
<role>
<name>manager</name>
<inheritFrom>employee</inheritFrom>
</role>
</roleSet>
<!--
- Set permissions for accessing application components here.
- resource -> property being access controlled.
- role -> group or user that can access resource.
- privilege -> privilege that role can use with resource.
-
- Each permission tag can contain multiple
- resources, roles, and privileges.
-->
<permissions>
<permission>
<resources>
<resource>contact_details</resource>
<resource>profile</resource>
</resources>
<roles>
<role>customer</role>
</roles>
<privileges>
<privilege>read</privilege>
<privilege>write</privilege>
</privileges>
</permission>
<permission>
<resources>
<resource>time_card</resource>
</resources>
<roles>
<role>employee</role>
</roles>
<privileges>
<privilege>read</privilege>
<privilege>write</privilege>
</privileges>
</permission>
<permission>
<resources>
<resource>time_card</resource>
</resources>
<roles>
<role>manager</role>
</roles>
<privileges>
<privilege>approve</privilege>
</privileges>
</permission>
</permissions>
</config>
Here is the code for the acl.py module:
"""Role based security"""
from xml.dom.minidom import parse
class AccessError(Exception):
pass
class Resource(object):
"""An Resource is an object that can be accessed by a Role."""
def __init__(self, name=''):
self.name = name
self._privileges = {}
def set_privilege(self, privilege, allowed=True):
self._privileges[privilege] = allowed
def has_access(self, privilege):
if privilege in self._privileges:
return self._privileges[privilege]
return False
def __str__(self):
rpr = self.name + ': '
for privilege, access in self._privileges.iteritems():
rpr += "%s:%s " % (privilege, access)
return rpr
class Role(object):
def __init__(self, name=''):
"""An Acl role has access to resources with specific privileges."""
self.name = name
self._parents = {}
self._resources = {}
def set_parent(self, parent):
self._parents[parent.name] = parent
def set_resource(self, resource):
self._resources[resource.name] = resource
def has_access(self, attr_name, privilege):
if attr_name in self._resources:
if self._resources[attr_name].has_access(privilege):
return True
for parent in self._parents.values():
if parent.has_access(attr_name, privilege):
return True
return False
def __str__(self):
rpr = self.name + ":\n"
rpr += "parents:\n"
for parent in self._parents.keys():
rpr += "\t%s\n" % parent
rpr += "resources:\n"
for resource in self._resources.values():
rpr += "\t%s\n" % resource.describe()
return rpr
class Acl(object):
"""Manages roles and resources.
Singleton class.
"""
class __impl:
"""Implementation of the singleton interface"""
def __init__(self):
self._acl = {}
def set_role(self, role):
self._acl[role.name] = role
def check_access(self, role_name, resource, privilege):
"""Check whether a role has access to a resource or not."""
if not role_name in self._acl:
raise AccessError('Role does not exist.')
return self._acl[role_name].has_access(resource, privilege)
def build_acl(self, file):
"""Build acl from an XML file."""
self._acl = {}
roles_to_create = {}
dom = parse(file)
# Find roles to create
roles_nodes = dom.getElementsByTagName('roleSet')
for roles_node in roles_nodes:
role_nodes = roles_node.getElementsByTagName('role')
for role_node in role_nodes:
name_nodes = role_node.getElementsByTagName('name')
parent_nodes = role_node.getElementsByTagName('inheritFrom')
role_name = name_nodes[0].childNodes[0].data
roles_to_create[role_name] = []
# Find role parents
for parent_node in parent_nodes:
roles_to_create[role_name].append(parent_node.childNodes[0].data)
# build inheritence chain
for role, parents in roles_to_create.iteritems():
self.set_role(self._create_role(role, roles_to_create))
# assign permissions
permissions = dom.getElementsByTagName('permissions')
for permissions_node in permissions:
permission_nodes = permissions_node.getElementsByTagName('permission')
for permission_node in permission_nodes:
resource_nodes = permission_node.getElementsByTagName('resource')
role_nodes = permission_node.getElementsByTagName('role')
privilege_nodes = permission_node.getElementsByTagName('privilege')
for resource_node in resource_nodes:
resource = Resource()
resource.name = resource_node.childNodes[0].data
for privilege_node in privilege_nodes:
resource.set_privilege(privilege_node.childNodes[0].data)
for role_node in role_nodes:
try:
role = self._acl[role_node.childNodes[0].data]
except:
raise AccessError('Role in permission is not defined.')
role.set_resource(resource)
def _create_role(self, role_name, roles_to_create):
"""Recursively create parent roles and then create child role."""
if role_name in self._acl:
role = self._acl[role_name]
else:
role = Role()
role.name = role_name
for parent_name in roles_to_create[role_name]:
if parent_name in self._acl:
parent = self._acl[parent_name]
else:
parent = self._create_role(parent_name, roles_to_create)
self.set_role(parent)
role.set_parent(parent)
return role
def __str__(self):
rpr = ''
for role in self._acl.values():
rpr += '----------\n'
rpr += role.describe()
return rpr
__instance = None
def __init__(self):
""" Create singleton instance """
# Check whether an instance already exists.
# If not, create it.
if Acl.__instance is None:
Acl.__instance = Acl.__impl()
self.__dict__['_Acl__instance'] = Acl.__instance
def __getattr__(self, attr):
""" Delegate get access to implementation """
return getattr(self.__instance, attr)
def __setattr__(self, attr, val):
""" Delegate set access to implementation """
return setattr(self.__instance, attr, val)
What module are you using to do this?
ReplyDeleteGreat rreading
ReplyDelete