diff --git a/addons/base_crypt/__init__.py b/addons/auth_crypt/__init__.py similarity index 95% rename from addons/base_crypt/__init__.py rename to addons/auth_crypt/__init__.py index 2534598a76f..c6086dd9725 100644 --- a/addons/base_crypt/__init__.py +++ b/addons/auth_crypt/__init__.py @@ -18,8 +18,7 @@ # ############################################################################## -from openerp.service import security -import crypt +import auth_crypt # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/base_crypt/__openerp__.py b/addons/auth_crypt/__openerp__.py similarity index 57% rename from addons/base_crypt/__openerp__.py rename to addons/auth_crypt/__openerp__.py index 97f6c98aeb8..f8d5c5bdce7 100644 --- a/addons/base_crypt/__openerp__.py +++ b/addons/auth_crypt/__openerp__.py @@ -19,35 +19,15 @@ # ############################################################################## { - 'name': 'DB Password Encryption', + 'name': 'Password Encryption', 'version': '1.1', 'author': ['OpenERP SA', 'FS3'], 'maintainer': 'OpenERP SA', 'website': 'http://www.openerp.com', 'category': 'Tools', 'description': """ -Replaces cleartext passwords in the database with a secure hash. -================================================================ - -For your existing user base, the removal of the cleartext passwords occurs -immediately when you install base_crypt. - -All passwords will be replaced by a secure, salted, cryptographic hash, -preventing anyone from reading the original password in the database. - -After installing this module, it won't be possible to recover a forgotten password -for your users, the only solution is for an admin to set a new password. - -Security Warning: ------------------ -Installing this module does not mean you can ignore other security measures, -as the password is still transmitted unencrypted on the network, unless you -are using a secure protocol such as XML-RPCS or HTTPS. - -It also does not protect the rest of the content of the database, which may -contain critical data. Appropriate security measures need to be implemented -by the system administrator in all areas, such as: protection of database -backups, system files, remote shell access, physical server access. +Ecrypted passwords +================== Interaction with LDAP authentication: ------------------------------------- diff --git a/addons/auth_crypt/auth_crypt.py b/addons/auth_crypt/auth_crypt.py new file mode 100644 index 00000000000..87b79931372 --- /dev/null +++ b/addons/auth_crypt/auth_crypt.py @@ -0,0 +1,150 @@ +# +# Implements encrypting functions. +# +# Copyright (c) 2008, F S 3 Consulting Inc. +# +# Maintainer: +# Alec Joseph Rivera (agifs3.ph) +# refactored by Antony Lesuisse openerp.com> +# + +import hashlib +import logging +from random import sample +from string import ascii_letters, digits + +import openerp +from openerp.osv import fields, osv + +_logger = logging.getLogger(__name__) + +magic_md5 = '$1$' + +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 res_users(osv.osv): + _inherit = "res.users" + + def set_pw(self, cr, uid, id, name, value, args, context): + if value: + encrypted = md5crypt(value, gen_salt()) + cr.execute('update res_users set password_crypt=%s where id=%s', (encrypted, 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), + 'password_crypt': fields.char(string='Encrypted Password', invisible=True), + } + + def check_credentials(self, cr, uid, password): + # convert to base_crypt if needed + cr.execute('SELECT password, password_crypt FROM res_users WHERE id=%s AND active', (uid,)) + if cr.rowcount: + stored_password, stored_password_crypt = cr.fetchone() + if password and not stored_password_crypt: + salt = gen_salt() + stored_password_crypt = md5crypt(stored_password, salt) + cr.execute("UPDATE res_users SET password='', password_crypt=%s WHERE id=%s", (stored_password_crypt, uid)) + try: + return super(res_users, self).check_credentials(cr, uid, password) + except openerp.exceptions.AccessDenied: + # check md5crypt + if stored_password_crypt[:len(magic_md5)] == "$1$": + salt = stored_password_crypt[len(magic_md5):11] + if stored_password_crypt == md5crypt(password, salt): + return + # Reraise password incorrect + raise + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/base_crypt/i18n/ar.po b/addons/auth_crypt/i18n/ar.po similarity index 100% rename from addons/base_crypt/i18n/ar.po rename to addons/auth_crypt/i18n/ar.po diff --git a/addons/base_crypt/i18n/base_crypt.pot b/addons/auth_crypt/i18n/base_crypt.pot similarity index 100% rename from addons/base_crypt/i18n/base_crypt.pot rename to addons/auth_crypt/i18n/base_crypt.pot diff --git a/addons/base_crypt/i18n/bg.po b/addons/auth_crypt/i18n/bg.po similarity index 100% rename from addons/base_crypt/i18n/bg.po rename to addons/auth_crypt/i18n/bg.po diff --git a/addons/base_crypt/i18n/ca.po b/addons/auth_crypt/i18n/ca.po similarity index 100% rename from addons/base_crypt/i18n/ca.po rename to addons/auth_crypt/i18n/ca.po diff --git a/addons/base_crypt/i18n/cs.po b/addons/auth_crypt/i18n/cs.po similarity index 100% rename from addons/base_crypt/i18n/cs.po rename to addons/auth_crypt/i18n/cs.po diff --git a/addons/base_crypt/i18n/da.po b/addons/auth_crypt/i18n/da.po similarity index 100% rename from addons/base_crypt/i18n/da.po rename to addons/auth_crypt/i18n/da.po diff --git a/addons/base_crypt/i18n/de.po b/addons/auth_crypt/i18n/de.po similarity index 100% rename from addons/base_crypt/i18n/de.po rename to addons/auth_crypt/i18n/de.po diff --git a/addons/base_crypt/i18n/el.po b/addons/auth_crypt/i18n/el.po similarity index 100% rename from addons/base_crypt/i18n/el.po rename to addons/auth_crypt/i18n/el.po diff --git a/addons/base_crypt/i18n/en_GB.po b/addons/auth_crypt/i18n/en_GB.po similarity index 100% rename from addons/base_crypt/i18n/en_GB.po rename to addons/auth_crypt/i18n/en_GB.po diff --git a/addons/base_crypt/i18n/es.po b/addons/auth_crypt/i18n/es.po similarity index 100% rename from addons/base_crypt/i18n/es.po rename to addons/auth_crypt/i18n/es.po diff --git a/addons/base_crypt/i18n/es_CL.po b/addons/auth_crypt/i18n/es_CL.po similarity index 100% rename from addons/base_crypt/i18n/es_CL.po rename to addons/auth_crypt/i18n/es_CL.po diff --git a/addons/base_crypt/i18n/es_CR.po b/addons/auth_crypt/i18n/es_CR.po similarity index 100% rename from addons/base_crypt/i18n/es_CR.po rename to addons/auth_crypt/i18n/es_CR.po diff --git a/addons/base_crypt/i18n/es_MX.po b/addons/auth_crypt/i18n/es_MX.po similarity index 100% rename from addons/base_crypt/i18n/es_MX.po rename to addons/auth_crypt/i18n/es_MX.po diff --git a/addons/base_crypt/i18n/es_PY.po b/addons/auth_crypt/i18n/es_PY.po similarity index 100% rename from addons/base_crypt/i18n/es_PY.po rename to addons/auth_crypt/i18n/es_PY.po diff --git a/addons/base_crypt/i18n/es_VE.po b/addons/auth_crypt/i18n/es_VE.po similarity index 100% rename from addons/base_crypt/i18n/es_VE.po rename to addons/auth_crypt/i18n/es_VE.po diff --git a/addons/base_crypt/i18n/et.po b/addons/auth_crypt/i18n/et.po similarity index 100% rename from addons/base_crypt/i18n/et.po rename to addons/auth_crypt/i18n/et.po diff --git a/addons/base_crypt/i18n/fa.po b/addons/auth_crypt/i18n/fa.po similarity index 100% rename from addons/base_crypt/i18n/fa.po rename to addons/auth_crypt/i18n/fa.po diff --git a/addons/base_crypt/i18n/fi.po b/addons/auth_crypt/i18n/fi.po similarity index 100% rename from addons/base_crypt/i18n/fi.po rename to addons/auth_crypt/i18n/fi.po diff --git a/addons/base_crypt/i18n/fr.po b/addons/auth_crypt/i18n/fr.po similarity index 100% rename from addons/base_crypt/i18n/fr.po rename to addons/auth_crypt/i18n/fr.po diff --git a/addons/base_crypt/i18n/gl.po b/addons/auth_crypt/i18n/gl.po similarity index 100% rename from addons/base_crypt/i18n/gl.po rename to addons/auth_crypt/i18n/gl.po diff --git a/addons/base_crypt/i18n/gu.po b/addons/auth_crypt/i18n/gu.po similarity index 100% rename from addons/base_crypt/i18n/gu.po rename to addons/auth_crypt/i18n/gu.po diff --git a/addons/base_crypt/i18n/hr.po b/addons/auth_crypt/i18n/hr.po similarity index 100% rename from addons/base_crypt/i18n/hr.po rename to addons/auth_crypt/i18n/hr.po diff --git a/addons/base_crypt/i18n/id.po b/addons/auth_crypt/i18n/id.po similarity index 100% rename from addons/base_crypt/i18n/id.po rename to addons/auth_crypt/i18n/id.po diff --git a/addons/base_crypt/i18n/it.po b/addons/auth_crypt/i18n/it.po similarity index 100% rename from addons/base_crypt/i18n/it.po rename to addons/auth_crypt/i18n/it.po diff --git a/addons/base_crypt/i18n/ja.po b/addons/auth_crypt/i18n/ja.po similarity index 100% rename from addons/base_crypt/i18n/ja.po rename to addons/auth_crypt/i18n/ja.po diff --git a/addons/base_crypt/i18n/lv.po b/addons/auth_crypt/i18n/lv.po similarity index 100% rename from addons/base_crypt/i18n/lv.po rename to addons/auth_crypt/i18n/lv.po diff --git a/addons/base_crypt/i18n/mn.po b/addons/auth_crypt/i18n/mn.po similarity index 100% rename from addons/base_crypt/i18n/mn.po rename to addons/auth_crypt/i18n/mn.po diff --git a/addons/base_crypt/i18n/nb.po b/addons/auth_crypt/i18n/nb.po similarity index 100% rename from addons/base_crypt/i18n/nb.po rename to addons/auth_crypt/i18n/nb.po diff --git a/addons/base_crypt/i18n/nl.po b/addons/auth_crypt/i18n/nl.po similarity index 100% rename from addons/base_crypt/i18n/nl.po rename to addons/auth_crypt/i18n/nl.po diff --git a/addons/base_crypt/i18n/nl_BE.po b/addons/auth_crypt/i18n/nl_BE.po similarity index 100% rename from addons/base_crypt/i18n/nl_BE.po rename to addons/auth_crypt/i18n/nl_BE.po diff --git a/addons/base_crypt/i18n/oc.po b/addons/auth_crypt/i18n/oc.po similarity index 100% rename from addons/base_crypt/i18n/oc.po rename to addons/auth_crypt/i18n/oc.po diff --git a/addons/base_crypt/i18n/pl.po b/addons/auth_crypt/i18n/pl.po similarity index 100% rename from addons/base_crypt/i18n/pl.po rename to addons/auth_crypt/i18n/pl.po diff --git a/addons/base_crypt/i18n/pt.po b/addons/auth_crypt/i18n/pt.po similarity index 100% rename from addons/base_crypt/i18n/pt.po rename to addons/auth_crypt/i18n/pt.po diff --git a/addons/base_crypt/i18n/pt_BR.po b/addons/auth_crypt/i18n/pt_BR.po similarity index 100% rename from addons/base_crypt/i18n/pt_BR.po rename to addons/auth_crypt/i18n/pt_BR.po diff --git a/addons/base_crypt/i18n/ro.po b/addons/auth_crypt/i18n/ro.po similarity index 100% rename from addons/base_crypt/i18n/ro.po rename to addons/auth_crypt/i18n/ro.po diff --git a/addons/base_crypt/i18n/ru.po b/addons/auth_crypt/i18n/ru.po similarity index 100% rename from addons/base_crypt/i18n/ru.po rename to addons/auth_crypt/i18n/ru.po diff --git a/addons/base_crypt/i18n/sk.po b/addons/auth_crypt/i18n/sk.po similarity index 100% rename from addons/base_crypt/i18n/sk.po rename to addons/auth_crypt/i18n/sk.po diff --git a/addons/base_crypt/i18n/sl.po b/addons/auth_crypt/i18n/sl.po similarity index 100% rename from addons/base_crypt/i18n/sl.po rename to addons/auth_crypt/i18n/sl.po diff --git a/addons/base_crypt/i18n/sq.po b/addons/auth_crypt/i18n/sq.po similarity index 100% rename from addons/base_crypt/i18n/sq.po rename to addons/auth_crypt/i18n/sq.po diff --git a/addons/base_crypt/i18n/sr@latin.po b/addons/auth_crypt/i18n/sr@latin.po similarity index 100% rename from addons/base_crypt/i18n/sr@latin.po rename to addons/auth_crypt/i18n/sr@latin.po diff --git a/addons/base_crypt/i18n/sv.po b/addons/auth_crypt/i18n/sv.po similarity index 100% rename from addons/base_crypt/i18n/sv.po rename to addons/auth_crypt/i18n/sv.po diff --git a/addons/base_crypt/i18n/tr.po b/addons/auth_crypt/i18n/tr.po similarity index 100% rename from addons/base_crypt/i18n/tr.po rename to addons/auth_crypt/i18n/tr.po diff --git a/addons/base_crypt/i18n/vi.po b/addons/auth_crypt/i18n/vi.po similarity index 100% rename from addons/base_crypt/i18n/vi.po rename to addons/auth_crypt/i18n/vi.po diff --git a/addons/base_crypt/i18n/zh_CN.po b/addons/auth_crypt/i18n/zh_CN.po similarity index 100% rename from addons/base_crypt/i18n/zh_CN.po rename to addons/auth_crypt/i18n/zh_CN.po diff --git a/addons/base_crypt/i18n/zh_TW.po b/addons/auth_crypt/i18n/zh_TW.po similarity index 100% rename from addons/base_crypt/i18n/zh_TW.po rename to addons/auth_crypt/i18n/zh_TW.po 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: