diff options
author | Marian Sigler <m@qjym.de> | 2012-09-21 06:18:38 +0200 |
---|---|---|
committer | Marian Sigler <m@qjym.de> | 2012-09-21 06:18:38 +0200 |
commit | ec2c11c9b21f7fcbf79bdf2b57eff911d8c66bd9 (patch) | |
tree | 480fca283d4a37f45fa49d3bc66da48c8080e027 /utils.py | |
parent | 67dbc8ad19e6ee1cc7f919ea837dd497a7e15bf9 (diff) | |
download | web-ec2c11c9b21f7fcbf79bdf2b57eff911d8c66bd9.tar.gz web-ec2c11c9b21f7fcbf79bdf2b57eff911d8c66bd9.tar.bz2 web-ec2c11c9b21f7fcbf79bdf2b57eff911d8c66bd9.zip |
Add confirmation to registration.
First, only ask for username and email, then send out a confirmation
mail. When the link therein is clicked, ask for a password and create
the account in LDAP.
Diffstat (limited to 'utils.py')
-rw-r--r-- | utils.py | 34 |
1 files changed, 24 insertions, 10 deletions
@@ -3,12 +3,16 @@ import hmac import ldap import pickle import re +import struct +import subprocess +from base64 import urlsafe_b64encode, urlsafe_b64decode from Crypto.Cipher import AES from email.mime.text import MIMEText from functools import wraps from flask import current_app, flash, g, redirect, render_template, request, session, url_for from hashlib import sha1 from random import randint +from time import time from werkzeug.exceptions import Forbidden @@ -86,7 +90,7 @@ def decrypt_password(ciphertext): return encryptor.decrypt(ciphertext[16:]).rstrip('\0') -def create_confirmation(realm, data): +def make_confirmation(realm, data): """ Create a confirmation token e.g. for confirmation mails. @@ -94,26 +98,36 @@ def create_confirmation(realm, data): some data (pickle-able). """ key = '\0'.join((current_app.config['SECRET_KEY'], realm)) - payload = pickle.dumps(data) + payload = ''.join((struct.pack('>i', time()), pickle.dumps(data))) mac = hmac.new(key, payload, sha1) - return ''.join((mac.digest(), payload)).encode('base64').strip() + return urlsafe_b64encode(''.join((mac.digest(), payload))).rstrip('=') -class InvalidConfirmation(ValueError): +class ConfirmationInvalid(ValueError): """Raised by `verify_confirmation` on invalid input data""" -def verify_confirmation(realm, token): +class ConfirmationTimeout(ValueError): + """Raised by `verify_confirmation` when the input data is too old""" + +def verify_confirmation(realm, token, timeout=None): """ - Verify a confirmation created by `create_confirmation` and, if it is + Verify a confirmation token created by `make_confirmation` and, if it is valid, return the original data. + If `timeout` is given, only accept the token if it is less than `timeout` + seconds old. """ key = '\0'.join((current_app.config['SECRET_KEY'], realm)) - token = token.decode('base64') + token = urlsafe_b64decode(token + '=' * (4 - len(token) % 4)) mac = token[:20] - payload = token[20:] + tokentime = struct.unpack('>i', token[20:24])[0] + payload = token[24:] + + if mac != hmac.new(key, token[20:], sha1).digest(): + raise ConfirmationInvalid('MAC does not match') - if mac != hmac.new(key, payload, sha1).digest(): - raise InvalidConfirmation('MAC does not match') + print '%d+%d=%d <> %d' % (tokentime, timeout, tokentime+timeout, time()) + if timeout is not None and time() > tokentime + timeout: + raise ConfirmationTimeout('Token is too old') return pickle.loads(payload) |