Authentication module for web.py 0.3

Warning: I coded this in 2008 for myself, but I haven't touched it or used web.py for more than ten years. I can't offer warranties of any kind but I hope that, somehow, the code can still be useful to you.

License: MIT

The module allows you to:

It also includes default pages to login, generate a password-reset token, email the token and set a new password after the token is validated.

zip file icon webpy_auth.zip

Installation

  1. Put the auth package in the web/contrib/ folder.
  2. Create the following tables:

    CREATE TABLE user (
        user_id             int NOT NULL AUTO_INCREMENT PRIMARY KEY,
        user_login          varchar(64) NOT NULL,
        user_password       varchar(255) NOT NULL,
        user_email          varchar(64),  # Optional, see settings
        user_status         varchar(16) NOT NULL DEFAULT 'active',
        user_last_login     datetime NOT NULL
    )
    
    CREATE TABLE permission (
        permission_id           int NOT NULL AUTO_INCREMENT PRIMARY KEY,
        permission_codename     varchar(50),  # Example: 'can_vote'
        permission_desc         varchar(50)   # Example: 'Can vote in elections'
    )
    
    CREATE TABLE user_permission (
        up_user_id          int REFERENCES user (user_id),
        up_permission_id    int REFERENCES permission (permission_id),
        PRIMARY KEY (up_user_id, up_permission_id)
    )
    
  3. Use in your code:

    import web
    from web.contrib.auth import DBAuth
    
    urls = (
        '/', 'index',
    )
    app = web.application(urls, locals())
    db = web.database(dbn='mysql', db='webpy', user='scott', pw='tiger')
    settings = {}
    
    auth = DBAuth(app, db, **settings)
    

    The system will create and use a DiskStore session. If you want to use an existing one or another type of session, you pass it as an argument.

    mysession = web.session.Session(app, web.session.DiskStore('sessions'))
    auth = DBAuth(app, db, mysession, **settings)
    

Usage

Once you have an DBAuth instance a number of methods are available on that object:

@auth.protected(**pars)
Decorator for limiting the access to pages.

Examples:

Limiting access to authenticated users

class somePage:
    @auth.protected()
    def GET(self):
        ...

Limiting access to users with a specific permission

class somePage:
    @auth.protected(perm='can_edit')
    def GET(self):
        ...

Limiting access to users who pass a test

def over18(user):
    return user.age > 18

class somePage:
    @auth.protected(test=over18)
    def GET(self):
        ...
If the user isn't authorized it'll be redirected to settings.url_login ('/login' by default).
auth.authenticate(login, password)
Validates the user's credentials. If they are valid returns a user object (minus the password hash) or None if not.
user = auth.authenticate(login='john', password='secret')
if not user:
    return 'That's correct'
else:
    return 'Wrong!'
This function does not log in the user. Use auth.login() for that.
auth.login(user)
Set the user as logged in.
auth.checkPassword(password, stored_passw)
Returns a boolean of whether the password was correct.
auth.logout()
Flush the authenticated user session
auth.userExist(login)
Return True if a user with that login already exist.
auth.createUser(login, password=None, perms=[], **data)
Create a new user and returns the user_id.
If password is None, it will marks the user as having no password (check_password() for this user will never return True).
auth.setPassword(login, password=None)
Sets the password of an already existing user to the given raw string, taking care of the password hashing.
auth.updateUser(login, **data)
Update the user's data taking care of the password hashing if one is provided.
auth.getUser(login=None)
Returns a user object (minus the password hash).
If login is None returns the currently authenticated user object or None if there isn't one
auth.passTest(user=None)
Return True if the user pass the test.
test must be a function that takes a user object and returns True or False.
auth.hasPerm(perm, user=None)
Return True if the user has the permission.
Perm can be either a single permission (string) or a sequence of them.
auth.getPermissions(user=None)
Returns a list of permission strings that the user has.
auth.createPermission(codename, desc)
Creates a new permission. If the permission already exists it update the description.
Example: createPermission('new_posts', 'Can write new posts')
auth.deletePermission(codename)
Deletes a permission
auth.addPermission(perm, user_id)
Assign an existing permission to a user.
auth.removePermission(perm, user_id)
Removes the permission.
auth.loginForm(auth)
A login form to be used inside other pages (like the home page).

Automatic views

By default the system will map a login, logout and password-reset pages. This can be disabled in the settings.

Settings

hash = 'sha512'
Either sha1, sha512 (default) or bcrypt — the algorithm used to perform a one-way hash of the password. Note that bcrypt is only supported on platforms that have the Python py-bcrypt module available.
hash_depth = 12
How many time the password is recursively hashed.
db_email_field = 'user_email'
Field of the user table that contains the email address. For instance, if you want to use the email as the username, you can change this to 'user_login'.
password_minlen = 6
Minimum password length. SetPassword() and createUser will raise an 'AuthError, 'bad password'' if the password is shorter than this.
forced_delay = 0.5
Artificial delay (in seconds) to slow down brute-force attacks
auto_map = True
Disable the auto-magically generated pages for login, logout and password reset. If it is True, it will use the url_* and template_* settings.
url_login = '/login'
The URL for the log in page.
url_logout = '/logout'
The URL for the log out.
url_after_login = '/'
Go there after a successful login
template_login = None
A template function:
render = web.template.render('/templates')
settings = dict(
    template_login = render.mylogin,
)
auth = DBAuth(app, db, **settings)
If None, the default template will be used. See web/contrib/auth/templates/login.html
url_reset_token = '/password_reset'
The URL of the password-reset token generation page.
url_reset_change = '/password_reset'
The URL for the password change page.
template_reset_token = None
A template function. If None, the default template will be used. See web/contrib/auth/templates/reset_token.html
template_reset_email = None
A template function. If None, the default template will be used. See web/contrib/auth/templates/reset_email.html
template_reset_change = None
A template function. If None, the default template will be used. See web/contrib/auth/templates/reset_change.html
reset_expire_after = 2
Number of hours than the password-reset token will be valid.
email_from = ''
The password-reset email “From:” header.