Fork me on GitHub

Cork - Authentication for the Bottle web framework

Cork provides a simple set of methods to implement Authentication and Authorization in web applications based on Bottle.

It is designed to stay out of the way and let you focus on what your application should do.

News:

  • 2013-01-27: Version 0.6
    • More flexible file naming in JsonBackend.
    • Fixed function to update user’s email address.
    • More informative log message for missing Pycrypto.
  • 2012-12-04: Version 0.5
    • SMTP SSL support added, smtp_url parsing improved.
    • requirements.txt added.
  • 2012-11-25: Version 0.4
    • Check added to prevent multiple registrations of the same account.
  • 2012-11-18: Version 0.3
    • PBKDF2 hash length check added
    • Multi-platform unit testing
  • 2012-10-04: Version 0.2
    • SMTP URL added: support for STARTTLS, SSL and configurable port numbers
    • Bugfix: login() redirects to fail_redirect if an username is not provided
    • Better password hashing, multiple hash formats supported
  • 2012-07-09: Version 0.1 - Improved installation
  • 2012-06-10: Version 0.1~beta3 - Improved registration and password reset

Cork is under development - contributions are welcome.

Features

  • Minimal design, easy to tweak.
  • Designed for web application with moderate userbases. User credentials are stored in JSON files.
  • Simple role-based authentication. User are authorized by role e.g. ‘admin’, ‘user’, ‘editor’.
    • Admin users can create and delete user accounts and roles.
  • User registration and password reset using email delivery and confirmation.
  • Unit-tested and almost fully code covered
  • Multiple backends support (e.g. storing users/roles in a key/value database).
  • Thread safe.

Roadmap

  • Additional hooks to provide logging or user-defined functions in case of login()/require() failure
  • Hooks to share session data between multiple hosts
  • Flask support

Basic usage

Installation:

$ pip install bottle-cork
or
$ easy_install bottle-cork

Use virtualenv on package-based Linux distributions! Learn why

A fully working example is provided with the Cork sources

Example web application:

from cork import Cork

# Use users.json and roles.json in the local example_conf directory
aaa = Cork('example_conf')

@bottle.route('/login', method='POST')
def login():
    username = request.POST.get('user', '')
    password = request.POST.get('pwd', '')
    aaa.login(username, password, success_redirect='/', fail_redirect='/login')

@bottle.route('/logout')
def logout():
    aaa.current_user.logout(redirect='/login')

@bottle.route('/')
def index():
    """Only authenticated users can see this"""
    aaa.require(fail_redirect='/sorry_page')
    return "Welcome %s" % aaa.current_user.username

@bottle.route('/admin')
def admin():
    """Only administrators can see this"""
    aaa.require(role='admin', fail_redirect='/sorry_page')
    return 'Welcome administrators'

@bottle.route('/register', method='POST')
def register():
    """Users can create new accounts, but only with 'user' role"""
    username = request.POST.get('user', '')
    password = request.POST.get('pwd', '')
    email_addr = request.POST.get('email_addr', '')
    aaa.register(username, password, email_addr)
    return 'Please check your inbox.'


# Web application main

def main():

    session_opts = {
        'session.type': 'cookie',
        'session.validate_key': True,
    }

    # Setup Beaker middleware to handle sessions and cookies
    app = bottle.default_app()
    app = SessionMiddleware(app, session_opts)

    # Start the Bottle webapp
    bottle.run(app=app, reloader=True)

if __name__ == "__main__":
    main()

Code documentation

exception cork.cork.AAAException[source]

Bases: exceptions.Exception

Generic Authentication/Authorization Exception

args
message
exception cork.cork.AuthException[source]

Bases: cork.cork.AAAException

Authentication Exception: incorrect username/password pair

args
message
class cork.cork.JsonBackend(directory, users_fname='users', roles_fname='roles', pending_reg_fname='register', initialize=False)[source]

Bases: object

Data storage class. Handles JSON files

Parameters:
  • users_fname (str.) – users file name (without .json)
  • roles_fname (str.) – roles file name (without .json)
  • pending_reg_fname (str.) – pending registrations file name (without .json)
  • initialize (bool.) – create empty JSON files (defaults to False)
save_users()

Save users in a JSON file

save_roles()

Save roles in a JSON file

save_pending_registrations()

Save pending registrations in a JSON file

class cork.cork.Cork(directory, email_sender=None, users_fname='users', roles_fname='roles', pending_reg_fname='register', initialize=False, session_domain=None, smtp_url='localhost', smtp_server=None)[source]

Bases: object

Auth/Authorization/Accounting class

Parameters:
  • directory (str.) – configuration directory
  • users_fname (str.) – users filename (without .json), defaults to ‘users’
  • roles_fname (str.) – roles filename (without .json), defaults to ‘roles’
login(username, password, success_redirect=None, fail_redirect=None)[source]

Check login credentials for an existing user. Optionally redirect the user to another page (tipically /login)

Parameters:
  • username (str.) – username
  • password (str.) – cleartext password
  • success_redirect (str.) – redirect authorized users (optional)
  • fail_redirect (str.) – redirect unauthorized users (optional)
Returns:

True for successful logins, else False

logout(success_redirect='/login', fail_redirect='/login')[source]

Log the user out, remove cookie

Parameters:
  • success_redirect (str.) – redirect the user after logging out
  • fail_redirect (str.) – redirect the user if it is not logged in
require(username=None, role=None, fixed_role=False, fail_redirect=None)[source]

Ensure the user is logged in has the required role (or higher). Optionally redirect the user to another page (tipically /login) If both username and role are specified, both conditions need to be satisfied. If none is specified, any authenticated user will be authorized. By default, any role with higher level than role will be authorized; set fixed_role=True to prevent this.

Parameters:
  • username (str.) – username (optional)
  • role (str.) – role
  • fixed_role (bool.) – require user role to match role strictly
  • redirect (str.) – redirect unauthorized users (optional)
create_role(role, level)[source]

Create a new role.

Parameters:
  • role (str.) – role name
  • level (int.) – role level (0=lowest, 100=admin)
Raises :

AuthException on errors

delete_role(role)[source]

Deleta a role.

Parameters:role (str.) – role name
Raises :AuthException on errors
list_roles()[source]

List roles.

Returns:(role, role_level) generator (sorted by role)
create_user(username, role, password, email_addr=None, description=None)[source]

Create a new user account. This method is available to users with level>=100

Parameters:
  • username (str.) – username
  • role (str.) – role
  • password (str.) – cleartext password
  • email_addr (str.) – email address (optional)
  • description (str.) – description (free form)
Raises :

AuthException on errors

delete_user(username)[source]

Delete a user account. This method is available to users with level>=100

Parameters:username (str.) – username
Raises :Exceptions on errors
list_users()[source]

List users.

Returns:(username, role, email_addr, description) generator (sorted by

username)

current_user[source]

Current autenticated user

Returns:User() instance, if authenticated
Raises :AuthException otherwise
user(username)[source]

Existing user

Returns:User() instance if the user exist, None otherwise
register(username, password, email_addr, role='user', max_level=50, subject='Signup confirmation', email_template='views/registration_email.tpl', description=None)[source]

Register a new user account. An email with a registration validation is sent to the user. WARNING: this method is available to unauthenticated users

Parameters:
  • username (str.) – username
  • password (str.) – cleartext password
  • role (str.) – role (optional), defaults to ‘user’
  • max_level (int.) – maximum role level (optional), defaults to 50
  • email_addr (str.) – email address
  • subject (str.) – email subject
  • email_template (str.) – email template filename
  • description (str.) – description (free form)
Raises :

AssertError or AAAException on errors

validate_registration(registration_code)[source]

Validate pending account registration, create a new account if successful.

Parameters:registration_code (str.) – registration code
send_password_reset_email(username=None, email_addr=None, subject='Password reset confirmation', email_template='views/password_reset_email')[source]

Email the user with a link to reset his/her password If only one parameter is passed, fetch the other from the users database. If both are passed they will be matched against the users database as a security check

Parameters:
  • username (str.) – username
  • email_addr (str.) – email address
  • subject (str.) – email subject
  • email_template (str.) – email template filename
Raises :

AAAException on missing username or email_addr, AuthException on incorrect username/email_addr pair

reset_password(reset_code, password)[source]

Validate reset_code and update the account password The username is extracted from the reset_code token

Parameters:
  • reset_code (str.) – reset token
  • password (str.) – new password
Raises :

AuthException for invalid reset tokens, AAAException

class cork.cork.User(username, cork_obj, session=None)[source]

Bases: object

Represent an authenticated user, exposing useful attributes: username, role, level, session_creation_time, session_accessed_time, session_id. The session-related attributes are available for the current user only.

Parameters:
  • username (str.) – username
  • cork_obj – instance of Cork
update(role=None, pwd=None, email_addr=None)[source]

Update an user account data

Parameters:
  • role (str.) – change user role, if specified
  • pwd (str.) – change user password, if specified
  • email_addr (str.) – change user email address, if specified
Raises :

AAAException on nonexistent user or role.

delete()[source]

Delete user account

Raises :AAAException on nonexistent user.
class cork.cork.Mailer(sender, smtp_url, join_timeout=5)[source]

Bases: object

Send emails asyncronously

Parameters:
  • sender (str.) – Sender email address
  • smtp_server (str.) – SMTP server
send_email(email_addr, subject, email_text)[source]

Send an email

Parameters:
  • email_addr (str.) – email address
  • subject (str.) – subject
  • email_text (str.) – email text
Raises :

AAAException if smtp_server and/or sender are not set

join()[source]

Flush email queue by waiting the completion of the existing threads

Returns:None

Indices and tables