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:
- Limit access to pages based on if the user is logged in, if is authorized (by checking against a table of permissions) or meet certain conditions.
- Generate and manage password hashes. Sha1, sha512 and bcrypt are supported.
- Authenticate a user by checking a login and password against a database of users.
- Generate and validate tokens for passwords resets.
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.
webpy_auth.zip
Installation
- Put the auth package in the web/contrib/ folder.
-
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)
)
-
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.