barrel

Flexible WSGI authentication and authorization tools.

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.

OptionDefaultDescription
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.

OptionDefaultDescription
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
templateTemplate(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

OptionDefaultDescription
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):
    def valid_user(self, username, password):
        return customauth.valid_user(username, password)


class MyBasic(Mixin, basic.BasicAuth): pass


class MyForm(Mixin, form.FormAuth): pass


class MyCombo(combo.ComboAuth):
    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))

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... :