From 3f2de50afccccedd5ccf6290b7bfb190bf49d0c5 Mon Sep 17 00:00:00 2001 From: Antony Lesuisse Date: Wed, 19 Dec 2012 12:20:31 +0100 Subject: [IMP] auth_crypt base_crypt cleanup bzr revid: al@openerp.com-20121219112031-mtogxyq1fxsbopz0 --- addons/base_crypt/crypt.py | 295 --------------------------------------------- 1 file changed, 295 deletions(-) delete mode 100644 addons/base_crypt/crypt.py (limited to 'addons/base_crypt/crypt.py') diff --git a/addons/base_crypt/crypt.py b/addons/base_crypt/crypt.py deleted file mode 100644 index 0cc218ed575..00000000000 --- a/addons/base_crypt/crypt.py +++ /dev/null @@ -1,295 +0,0 @@ -# -# Implements encrypting functions. -# -# Copyright (c) 2008, F S 3 Consulting Inc. -# -# Maintainer: -# Alec Joseph Rivera (agifs3.ph) -# -# -# Warning: -# ------- -# -# This program as such is intended to be used by professional programmers -# who take the whole responsibility of assessing all potential consequences -# resulting from its eventual inadequacies and bugs. End users who are -# looking for a ready-to-use solution with commercial guarantees and -# support are strongly adviced to contract a Free Software Service Company. -# -# This program is Free Software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by the -# Free Software Foundation; either version 2 of the License, or (at your -# option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General -# Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the: -# -# Free Software Foundation, Inc. -# 59 Temple Place - Suite 330 -# Boston, MA 02111-1307 -# USA. - -import hashlib -import logging -from random import sample -from string import ascii_letters, digits - -from openerp import pooler -from openerp.osv import fields,osv -from openerp.tools.translate import _ -from openerp.service import security - -magic_md5 = '$1$' -_logger = logging.getLogger(__name__) - -def gen_salt(length=8, symbols=None): - if symbols is None: - symbols = ascii_letters + digits - return ''.join(sample(symbols, length)) - - -def md5crypt( raw_pw, salt, magic=magic_md5 ): - """ md5crypt FreeBSD crypt(3) based on but different from md5 - - The md5crypt is based on Mark Johnson's md5crypt.py, which in turn is - based on FreeBSD src/lib/libcrypt/crypt.c (1.2) by Poul-Henning Kamp. - Mark's port can be found in ActiveState ASPN Python Cookbook. Kudos to - Poul and Mark. -agi - - Original license: - - * "THE BEER-WARE LICENSE" (Revision 42): - * - * wrote this file. As long as you retain this - * notice you can do whatever you want with this stuff. If we meet some - * day, and you think this stuff is worth it, you can buy me a beer in - * return. - * - * Poul-Henning Kamp - """ - raw_pw = raw_pw.encode('utf-8') - salt = salt.encode('utf-8') - hash = hashlib.md5() - hash.update( raw_pw + magic + salt ) - st = hashlib.md5() - st.update( raw_pw + salt + raw_pw) - stretch = st.digest() - - for i in range( 0, len( raw_pw ) ): - hash.update( stretch[i % 16] ) - - i = len( raw_pw ) - - while i: - if i & 1: - hash.update('\x00') - else: - hash.update( raw_pw[0] ) - i >>= 1 - - saltedmd5 = hash.digest() - - for i in range( 1000 ): - hash = hashlib.md5() - - if i & 1: - hash.update( raw_pw ) - else: - hash.update( saltedmd5 ) - - if i % 3: - hash.update( salt ) - if i % 7: - hash.update( raw_pw ) - if i & 1: - hash.update( saltedmd5 ) - else: - hash.update( raw_pw ) - - saltedmd5 = hash.digest() - - itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' - - rearranged = '' - for a, b, c in ((0, 6, 12), (1, 7, 13), (2, 8, 14), (3, 9, 15), (4, 10, 5)): - v = ord( saltedmd5[a] ) << 16 | ord( saltedmd5[b] ) << 8 | ord( saltedmd5[c] ) - - for i in range(4): - rearranged += itoa64[v & 0x3f] - v >>= 6 - - v = ord( saltedmd5[11] ) - - for i in range( 2 ): - rearranged += itoa64[v & 0x3f] - v >>= 6 - - return magic + salt + '$' + rearranged - - -class users(osv.osv): - _name="res.users" - _inherit="res.users" - # agi - 022108 - # Add handlers for 'input_pw' field. - - def set_pw(self, cr, uid, id, name, value, args, context): - if value: - obj = pooler.get_pool(cr.dbname).get('res.users') - if not hasattr(obj, "_salt_cache"): - obj._salt_cache = {} - - salt = obj._salt_cache[id] = gen_salt() - encrypted = md5crypt(value, salt) - - else: - #setting a password to '' is allowed. It can be used to inactivate the classic log-in of the user - #while the access can still be granted by another login method (openid...) - encrypted = '' - cr.execute('update res_users set password=%s where id=%s', - (encrypted.encode('utf-8'), int(id))) - del value - - def get_pw( self, cr, uid, ids, name, args, context ): - cr.execute('select id, password from res_users where id in %s', (tuple(map(int, ids)),)) - stored_pws = cr.fetchall() - res = {} - - for id, stored_pw in stored_pws: - res[id] = stored_pw - - return res - - _columns = { - 'password': fields.function(get_pw, fnct_inv=set_pw, type='char', string='Password', invisible=True, store=True), - } - - def login(self, db, login, password): - if not password: - return False - if db is False: - raise RuntimeError("Cannot authenticate to False db!") - cr = None - try: - cr = pooler.get_db(db).cursor() - return self._login(cr, db, login, password) - except Exception: - _logger.exception('Cannot authenticate.') - return Exception('Access denied.') - finally: - if cr is not None: - cr.close() - - def _login(self, cr, db, login, password): - cr.execute( 'SELECT password, id FROM res_users WHERE login=%s AND active', - (login.encode('utf-8'),)) - - if cr.rowcount: - stored_pw, id = cr.fetchone() - else: - # Return early if no one has a login name like that. - return False - - stored_pw = self.maybe_encrypt(cr, stored_pw, id) - - if not stored_pw: - # means couldn't encrypt or user is not active! - return False - - # Calculate an encrypted password from the user-provided - # password. - obj = pooler.get_pool(db).get('res.users') - if not hasattr(obj, "_salt_cache"): - obj._salt_cache = {} - salt = obj._salt_cache[id] = stored_pw[len(magic_md5):11] - encrypted_pw = md5crypt(password, salt) - - # Check if the encrypted password matches against the one in the db. - cr.execute("""UPDATE res_users - SET login_date=now() AT TIME ZONE 'UTC' - WHERE id=%s AND password=%s AND active - RETURNING id""", - (int(id), encrypted_pw.encode('utf-8'))) - res = cr.fetchone() - cr.commit() - - if res: - return res[0] - else: - return False - - def check(self, db, uid, passwd): - if not passwd: - # empty passwords disallowed for obvious security reasons - raise security.ExceptionNoTb('AccessDenied') - - # Get a chance to hash all passwords in db before using the uid_cache. - obj = pooler.get_pool(db).get('res.users') - if not hasattr(obj, "_salt_cache"): - obj._salt_cache = {} - self._uid_cache.get(db, {}).clear() - - cached_pass = self._uid_cache.get(db, {}).get(uid) - if (cached_pass is not None) and cached_pass == passwd: - return True - - cr = pooler.get_db(db).cursor() - try: - if uid not in self._salt_cache.get(db, {}): - # If we don't have cache, we have to repeat the procedure - # through the login function. - cr.execute( 'SELECT login FROM res_users WHERE id=%s', (uid,) ) - stored_login = cr.fetchone() - if stored_login: - stored_login = stored_login[0] - - res = self._login(cr, db, stored_login, passwd) - if not res: - raise security.ExceptionNoTb('AccessDenied') - else: - salt = self._salt_cache[db][uid] - cr.execute('SELECT COUNT(*) FROM res_users WHERE id=%s AND password=%s AND active', - (int(uid), md5crypt(passwd, salt))) - res = cr.fetchone()[0] - finally: - cr.close() - - if not bool(res): - raise security.ExceptionNoTb('AccessDenied') - - if res: - if self._uid_cache.has_key(db): - ulist = self._uid_cache[db] - ulist[uid] = passwd - else: - self._uid_cache[db] = {uid: passwd} - return bool(res) - - def maybe_encrypt(self, cr, pw, id): - """ Return the password 'pw', making sure it is encrypted. - - If the password 'pw' is not encrypted, then encrypt all active passwords - in the db. Returns the (possibly newly) encrypted password for 'id'. - """ - - if not pw.startswith(magic_md5): - cr.execute("SELECT id, password FROM res_users WHERE active=true AND password NOT LIKE '$%'") - # Note that we skip all passwords like $.., in anticipation for - # more than md5 magic prefixes. - res = cr.fetchall() - for i, p in res: - encrypted = md5crypt(p, gen_salt()) - cr.execute('UPDATE res_users SET password=%s where id=%s', (encrypted, i)) - if i == id: - encrypted_res = encrypted - cr.commit() - return encrypted_res - return pw - - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: -- cgit v1.2.3