Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/tonyseek/simple-rbac

A simple role based access control utility for Python.
https://github.com/tonyseek/simple-rbac

Last synced: 3 months ago
JSON representation

A simple role based access control utility for Python.

Awesome Lists containing this project

README

        

|Build Status| |Coverage Status| |PyPI Version| |Wheel Status|

Simple RBAC
===========

This is a simple role based access control utility in Python.

Quick Start
-----------

1. Install Simple RBAC
~~~~~~~~~~~~~~~~~~~~~~

::

pip install simple-rbac

2. Create a Access Control List
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

::

import rbac.acl

acl = rbac.acl.Registry()

3. Register Roles and Resources
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

::

acl.add_role("member")
acl.add_role("student", ["member"])
acl.add_role("teacher", ["member"])
acl.add_role("junior-student", ["student"])

acl.add_resource("course")
acl.add_resource("senior-course", ["course"])

4. Add Rules
~~~~~~~~~~~~

::

acl.allow("member", "view", "course")
acl.allow("student", "learn", "course")
acl.allow("teacher", "teach", "course")
acl.deny("junior-student", "learn", "senior-course")

5. Use It to Check Permission
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

::

if acl.is_allowed("student", "view", "course"):
print("Students chould view courses.")
else:
print("Students chould not view courses.")

if acl.is_allowed("junior-student", "learn", "senior-course"):
print("Junior students chould learn senior courses.")
else:
print("Junior students chould not learn senior courses.")

Custom Role and Resource Class
------------------------------

It’s not necessary to use string as role object and resource object like
"Quick Start". You could define role class and resource class of
yourself, such as a database mapped model in SQLAlchemy.

Whatever which role class and resource class you will use, it must
implement ``__hash__`` method and ``__eq__`` method to be `hashable`_.

Example
~~~~~~~

::

class Role(db.Model):
"""The role."""

id = db.Column(db.Integer, primary_key=True)
screen_name = db.Column(db.Unicode, nullable=False, unique=True)

def __hash__(self):
return hash("ROLE::%d" % self.id)

def __eq__(self, other):
return self.id == other.id

class Resource(db.Model):
"""The resource."""

id = db.Column(db.Integer, primary_key=True)
screen_name = db.Column(db.Unicode, nullable=False, unique=True)

def __hash__(self):
return hash("RESOURCE::%d" % self.id)

def __eq__(self, other):
return self.id == other.id

Of course, You could use the built-in hashable types too, such as tuple,
namedtuple, frozenset and more.

Use the Identity Context Check Your Permission
----------------------------------------------

Obviously, the work of checking permission is a cross-cutting concern.
The module named ``rbac.context``, our ``IdentityContext``, provide some
ways to make our work neater.

1. Create the Context Manager
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

::

acl = Registry()
context = IdentityContext(acl)

2. Set a Loader
~~~~~~~~~~~~~~~

The loader should load the roles of current user.

::

from myapp import get_current_user

@context.set_roles_loader
def second_load_roles():
user = get_current_user()
yield "everyone"
for role in user.roles:
yield str(role)

3. Protect Your Action
~~~~~~~~~~~~~~~~~~~~~~

Now you could protect your action from unauthorized access. As you
please, you could choose many ways to check the permission, including
python ``decorator``, python ``with statement`` or simple method
calling.

Decorator
^^^^^^^^^

::

@context.check_permission("view", "article", message="can't view")
def article_page():
return "your-article"

With Statement
^^^^^^^^^^^^^^

::

def article_page():
with context.check_permission("view", "article", message="can't view"):
return "your-article"

Simple Method Calling
^^^^^^^^^^^^^^^^^^^^^

::

def article_page():
context.check_permission("view", "article", message="can't view").check()
return "your-article"

Exception Handler and Non-Zero Checking
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Whatever which way you choosen, a exception
``rbac.context.PermissionDenied`` will be raised while a unauthorized
access happening. The keyword arguments sent to the
``context.check_permission`` will be set into a attirbute named
``kwargs`` of the exception. You could get those data in your exception
handler.

::

@context.check_permission("view", "article", message="can not view")
def article_page():
return "your-article"

try:
print article_page()
except PermissionDenied as exception:
print "The access has been denied, you %s" % exception.kwargs['message']

If you don’t want to raise the exception but only check the access is
allowed or not, you could use the checking like a boolean value.

::

if not context.check_permission("view", "article"):
print "Oh! the access has been denied."

is_allowed = bool(context.check_permission("view", "article"))

.. _hashable: http://docs.python.org/glossary.html#term-hashable

.. |Build Status| image:: https://img.shields.io/travis/tonyseek/simple-rbac.svg?style=flat
:target: https://travis-ci.org/tonyseek/simple-rbac
:alt: Build Status
.. |Coverage Status| image:: https://img.shields.io/coveralls/tonyseek/simple-rbac.svg?style=flat
:target: https://coveralls.io/r/tonyseek/simple-rbac
:alt: Coverage Status
.. |Wheel Status| image:: https://img.shields.io/pypi/wheel/simple-rbac.svg?style=flat
:target: https://warehouse.python.org/project/simple-rbac
:alt: Wheel Status
.. |PyPI Version| image:: https://img.shields.io/pypi/v/simple-rbac.svg?style=flat
:target: https://pypi.python.org/pypi/simple-rbac
:alt: PyPI Version