A pyramid authorization (not authentication) suite
Project description
The pyramid_authz Python package provides helper routines to make the authorization component of access control easier. Note that this package does NOT address authentication in any way (there are many other packages for that). Authentication is the process of determining who the request is coming from, authorization is the process of determining what that identity is allowed to do.
This package exposes a postgres-like approach to access control, which basically means that access control is broken down into “roles” and “privileges”.
In short:
A Privilege is the permission to perform an action;
A Role is a collection of privileges;
Roles can inherit from other roles;
Any database object can be made to be a role; and
Access to a resource or action is always based on privileges, never on roles, i.e. your code should always ask “does this user have this privilege”, not “is this user a member of this role”.
For more information on postgres’ approach, please see http://www.postgresql.org/docs/9.0/static/user-manag.html.
Project
Installation
$ pip install pyramid_authz
Usage
Require static privilege user.valid:
from pyramid_authz import privilege
# restrict the 'core' view to authenticated users
@view_config(route_name='core')
@privilege('user.valid')
def core(request):
...
Require dynamic privilege for path route /blog/{blog_id}/{page_id} which depends on which blog, which page, and what method is being requested:
from pyramid_authz import privilege, Method, PathParam
# restrict the 'blog.page' view to users that have the blog-
# and method-specific privilege
@view_config(route_name='blog.page')
def blog(request):
blog_id = request.matchdict['blog_id']
page_id = request.matchdict['page_id']
priv = privilege(blog_id=blog_id, page_id=page_id, method=request.method)
# check
if not priv.allow(request):
raise HTTPForbidden()
# same as check, but also raises the exception all-in-one
priv.require(request)
# same, but raise 404 instead 401/403
priv.require(request, failto=HTTPNotFound)
...
Same thing, but using the declarative helpers PathParam (which returns the specified request.matchdict[{PARAMNAME}] path component) and Method (which returns the value of request.method):
Method (
# same thing, but specified declaratively:
from pyramid_authz import privilege, PathParam, Method
@view_config(route_name='blog.page')
@privilege(
blog_id = PathParam('blog_id'),
page_id = PathParam('page_id'),
method = RequestMethod,
)
def blog(request):
...