About
This distribution provides a variety of access control middlewares. Convenience functions which can be used as decorators are included. The classes have useful defaults yet are highly configurable. All interfaces are designed to be easily customized and extended. Currently supports HTTP Basic and Web forms authentication, roles-based authorization and is flup session compatible out of the box. (It is no problem to use some other type of sessions or none.)
Download
Download the latest release from barrel's Cheese Shop Page.
Blessed are the cheesemakers!
Basic Usage
If you want to limit access to a simple WSGI app to only admins, using a web form for authentication:
from barrel import cooper
logins = [('joe', 'foo'), ('sam', 'eggs'), ('mark', 'that')]
roles = dict(joe=['admin', 'user'], sam=['user'])
@cooper.formauth(users=logins)
@cooper.rolesauthz(roles=roles_dict, allowed_roles=['admin'])
def my_app(environ, start_response):
...
formauth adds form based authentication
(without redirecting to another resource).
rolesauthz adds roles based authorization.
Other decorators in the cooper module are
basicauth which handles HTTP basic auth
and comboauth which will perform basic
auth if an HTTP AUTHORIZATION header is sent or falls
back to Web form based authentication if it is not.
This is handy if you want some part of your user
interface to double as a web service.
Each decorator takes various options as keyword args. Other options passed will simply be ignored.
cooper.basicauth Options
These options become the attributes of a barrel.basic.BasicAuth
instance which is created by this decorator.
| Option | Default | Description |
|---|---|---|
users | [] | list of (username, password) tuples |
realm | 'GenericRealm' | The realm to be used for HTTP Basic auth |
session_key | 'com.saddi.service.session' | The key to find the session service in the environ |
session_user_key | 'barrel.user' | The key in the session dict |
cooper.formauth Options
These options become the attributes of a barrel.basic.BasicAuth
instance which is created by this decorator.
| Option | Default | Description |
|---|---|---|
users | [] | A list of (username, password) tuples |
session_key | 'com.saddi.service.session' | The key to find the session service in the environ |
session_user_key | 'barrel.user' | The key in the session dict |
user_field | 'username' | The username field id (for the HTML) |
pass_field | 'password' | The password field id (for the HTML) |
button | 'barrel-form-button' | The submit button id (for the HTML) |
environ_user_key | 'barrel.form.username' | Where to put the keep the username during the authentication attempt |
first_message | "Please enter your username and password" | Message on the form when before the first attempt |
failed_message | "Sign in failed; please try again" | Message on the form after a failed attempt |
template | Template(barrel.form.default_template) | A string.Template used to create the authentication page |
cooper.comboauth Options
All the options of basicauth and
formauth can be passed.
This decorator uses cooper.combo.BasicFormAuth
which passes options on to an instance of
barrel.basic.BasicAuth and an instance of
barrel.form.FormAuth to which it
delegates based on finding an AUTHORIZATION header or not.
cooper.rolesauthz Options
| Option | Default | Description |
|---|---|---|
allowed_roles | [] | Just like it sounds |
roles_dict | 'com.saddi.service.session' | Usernames and lists of their roles |
environ_roles_key | 'barrel.roles' | Where to store roles in the environ |
session_key | 'com.saddi.service.session' | The key to find the session service in the environ |
session_roles_key | 'barrel.roles' | Where to store roles in the session |
Real Life
In real life you will need the option of controlling every aspect of authentication and authorization. From how credentials and roles are verified, to how to respond to authentication and authorization failure. The classes in this package are composed of well specialized methods so that you can easily override the parts that you want in order to customize... well, everything.
Example: Custom Combo and Roles
The most common case for customization
(perhaps the most common use case for barrel)
is to check username/password against and/or
pull roles from a database/directory/web service.
For the example we will pretend that we have
implemented a module called customauth that
looks in our directory service/database/whatever for us.
We will integrate it like so:
from barrel import basic, form, combo, roles, cooper
import customauth
class MixIn(object):
session_key = 'beaker.session'
realm = 'MyRealm'
def valid_user(self, username, password):
return customauth.valid_user(username, password)
def session_dict(self, environ):
return environ.get(self.session_key, {})
class MyBasic(MixIn, basic.BasicAuth): pass
class MyForm(MixIn, form.FormAuth): pass
class MyCombo(combo.BasicFormAuth):
basic_auth = MyBasic
form_auth = MyForm
my_authn = cooper.decorize(MyCombo)
class MyRoles(roles.RolesAuthz):
def user_roles(self, username):
return customauth.user_roles(username)
my_authz = cooper.decorize(MyRoles)
def secure(*allowed_roles):
"""Decorator to secure my apps with."""
def deco(app):
return my_authn(my_authz(app, allowed_roles=allowed_roles))
return deco
With that you can now secure all your WSGI callables like this:
@secure('admin', 'manager')
def my_app(environ, start_response):
...
This only scratches the surface of what you could do. As mentioned previously, it is possible to override any and every aspect of the behavior of these classes. I have tried hard to make doing so as natural as possible so just take a look at the source code and it will probably not be too hard to figure out what to do.
Questions, comments, suggestions, bugs... : luke.arno@gmail.com