# -*- coding: utf-8 -*- import ldap import re from functools import wraps from flask import flash, g, redirect, render_template, request, session, url_for from random import randint from Crypto.Cipher import AES from werkzeug.exceptions import Forbidden _username_re = re.compile(r'^[a-z]{2,16}') # using http://flask.pocoo.org/docs/patterns/viewdecorators/ def templated(template=None): def templated_(f): @wraps(f) def templated__(*args, **kwargs): template_name = template if template_name is None: template_name = request.endpoint \ .replace('.', '/') + '.html' ctx = f(*args, **kwargs) if ctx is None: ctx = {} elif not isinstance(ctx, dict): return ctx return render_template(template_name, **ctx) return templated__ return templated_ def login_required(f): @wraps(f) def login_required_(*args, **kwargs): if not g.user: raise Forbidden return f(*args, **kwargs) return login_required_ def login_user(username, password): try: g.user = g.ldap.auth(username, password) except ldap.INVALID_CREDENTIALS: return False session['username'] = username session['password'] = encrypt_password(password) return True def logout_user(): session.pop('username', None) session.pop('password', None) g.user = None def pad(s, numbytes=32, padding='\0'): return s + (numbytes - len(s) % numbytes) * padding def encrypt_password(password): """ Encrypt the given password with `config.PASSWORD_ENCRYPTION_KEY`. The key must be 32 bytes long. """ assert len(app.config['PASSWORD_ENCRYPTION_KEY']) == 32 if isinstance(password, unicode): password = password.encode('utf8') iv = ''.join(chr(randint(0, 0xff)) for i in range(16)) encryptor = AES.new(app.config['PASSWORD_ENCRYPTION_KEY'], AES.MODE_CBC, iv) return iv + encryptor.encrypt(pad(password)) def decrypt_password(ciphertext): """ Decrypt the given password with `config.PASSWORD_ENCRYPTION_KEY`. """ iv = ciphertext[:16] encryptor = AES.new(app.config['PASSWORD_ENCRYPTION_KEY'], AES.MODE_CBC, iv) return encryptor.decrypt(ciphertext[16:]).rstrip('\0') # circular import from app import app