xrg has proposed merging lp:~xrg/openobject-addons/trunk-patch20 into lp:~openerp-dev/openobject-addons/trunk-dev-addons1.
Requested reviews: OpenERP R&D Team (openerp-dev) For more details, see: https://code.launchpad.net/~xrg/openobject-addons/trunk-patch20/+merge/45871 -- https://code.launchpad.net/~xrg/openobject-addons/trunk-patch20/+merge/45871 Your team OpenERP R&D Team is requested to review the proposed merge of lp:~xrg/openobject-addons/trunk-patch20 into lp:~openerp-dev/openobject-addons/trunk-dev-addons1.
=== added file 'base_crypt/__openerp__.py' --- base_crypt/__openerp__.py 1970-01-01 00:00:00 +0000 +++ base_crypt/__openerp__.py 2011-01-11 15:51:39 +0000 @@ -0,0 +1,32 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +############################################################################## +{ + "name" : "Base - Password Encryption", + "version" : "1.0", + "author" : "FS3 , Review Tiny", + "website" : "http://www.openerp.com", + "category" : "Generic Modules/Base", + "description": "Module for password encryption.", + "depends" : ["base"], + "data" : [], + "active": False, + "installable": True, +} === renamed file 'base_crypt/__openerp__.py' => 'base_crypt/__openerp__.py.THIS' === modified file 'base_crypt/crypt.py' (properties changed: +x to -x) --- base_crypt/crypt.py 2010-12-30 06:09:52 +0000 +++ base_crypt/crypt.py 2011-01-11 15:51:39 +0000 @@ -37,14 +37,14 @@ # USA. from random import seed, sample -from string import letters, digits +from string import ascii_letters, digits from osv import fields,osv import pooler from tools.translate import _ magic_md5 = '$1$' -def gen_salt( length=8, symbols=letters + digits ): +def gen_salt( length=8, symbols=ascii_letters + digits ): seed() return ''.join( sample( symbols, length ) ) @@ -64,11 +64,15 @@ # * # * Poul-Henning Kamp -import md5 +#TODO: py>=2.6: from hashlib import md5 +import hashlib def encrypt_md5( raw_pw, salt, magic=magic_md5 ): - hash = md5.new( raw_pw + magic + salt ) - stretch = md5.new( raw_pw + salt + raw_pw).digest() + 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] ) @@ -85,7 +89,7 @@ saltedmd5 = hash.digest() for i in range( 1000 ): - hash = md5.new() + hash = hashlib.md5() if i & 1: hash.update( raw_pw ) @@ -162,19 +166,37 @@ } def login(self, db, login, password): - cr = pooler.get_db(db).cursor() - cr.execute('select password, id from res_users where login=%s', + 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: + import logging + logging.getLogger('netsvc').exception('Could not 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', (login.encode('utf-8'),)) - stored_pw = id = cr.fetchone() - if stored_pw: - stored_pw = stored_pw[0] - id = id[1] + if cr.rowcount: + stored_pw, id = cr.fetchone() else: - # Return early if there is no such login. + # 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. @@ -183,12 +205,14 @@ obj._salt_cache = {} salt = obj._salt_cache[id] = stored_pw[len(magic_md5):11] encrypted_pw = encrypt_md5(password, salt) - + # Check if the encrypted password matches against the one in the db. - cr.execute('select id from res_users where id=%s and password=%s and active', (int(id), encrypted_pw.encode('utf-8'))) + cr.execute('UPDATE res_users SET date=now() ' \ + 'WHERE id=%s AND password=%s AND active RETURNING id', + (int(id), encrypted_pw.encode('utf-8'))) res = cr.fetchone() - cr.close() - + cr.commit() + if res: return res[0] else: @@ -206,6 +230,7 @@ return True cr = pooler.get_db(db).cursor() +<<<<<<< TREE if uid not in obj._salt_cache: cr.execute('select login from res_users where id=%s', (int(uid),)) stored_login = cr.fetchone() @@ -220,8 +245,30 @@ (int(uid), encrypt_md5(passwd, salt))) res = cr.fetchone()[0] cr.close() +======= + 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', + (int(uid), encrypt_md5(passwd, salt))) + res = cr.fetchone()[0] + finally: + cr.close() + +>>>>>>> MERGE-SOURCE if not bool(res): - raise Exception('AccessDenied') + raise security.ExceptionNoTb('AccessDenied') if res: if self._uid_cache.has_key(db): @@ -230,20 +277,25 @@ else: self._uid_cache[db] = {uid: passwd} return bool(res) - + def maybe_encrypt(self, cr, pw, id): - # If the password 'pw' is not encrypted, then encrypt all passwords - # in the db. Returns the (possibly newly) encrypted password for '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 pw[0:len(magic_md5)] != magic_md5: - cr.execute('select id, password from res_users') + if not pw.startswith(magic_md5): + encrypted_res = False + 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 = p - if p[0:len(magic_md5)] != magic_md5: - encrypted = encrypt_md5(p, gen_salt()) - cr.execute('update res_users set password=%s where id=%s', - (encrypted.encode('utf-8'), int(i))) + encrypted = encrypt_md5(p, gen_salt()) + cr.execute('UPDATE res_users SET password=%s where id=%s', + (encrypted, i)) if i == id: encrypted_res = encrypted cr.commit() === added file 'base_crypt/i18n/el.po' --- base_crypt/i18n/el.po 1970-01-01 00:00:00 +0000 +++ base_crypt/i18n/el.po 2011-01-11 15:51:39 +0000 @@ -0,0 +1,27 @@ +# Translation of OpenERP Server. +# This file contains the translation of the following modules: +# * base_crypt +# +# Copyright (C) 2008,2009 P. Christeas <[email protected]> +# <> <>, 2009. +msgid "" +msgstr "" +"Project-Id-Version: OpenERP Server 5.0.0\n" +"Report-Msgid-Bugs-To: [email protected]\n" +"POT-Creation-Date: 2009-05-30 15:14:08+0000\n" +"PO-Revision-Date: 2009-03-27 14:30+0200\n" +"Last-Translator: <> <>\n" +"Language-Team: <>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#~ msgid "Module for password encryption." +#~ msgstr "ÎÏθÏÏμα για κÏÏ ÏÏογÏάÏηÏη κÏδικÏν." + +#~ msgid "Invalid XML for View Architecture!" +#~ msgstr "ÎÎºÏ Ïο XML για αÏÏιÏεκÏονική ÏÏοβολήÏ!" + +#~ msgid "Password" +#~ msgstr "ÎÏδικÏÏ" === modified file 'base_setup/__init__.py' --- base_setup/__init__.py 2010-11-19 13:48:01 +0000 +++ base_setup/__init__.py 2011-01-11 15:51:39 +0000 @@ -45,9 +45,15 @@ def get_users(self, cr, uid, context=None): user_obj = self.pool.get('res.users') user_ids = user_obj.search(cr, uid, []) - users = user_obj.browse(cr, uid, user_ids, context=context) - user_str = '\n'.join(map(lambda x: ' - %s :\n\t\tLogin : %s \n\t\tPassword : %s' % (x.name, x.login, x.password), users)) - return _('The following users have been installed : \n')+ user_str + user_list = [] + user_tmpl_nopass = _(' - %s :\n\t\tLogin : %s') + user_tmpl_pass = _(' - %s :\n\t\tLogin : %s \n\t\tPassword : %s') + for user in user_obj.browse(cr, uid, user_ids, context=context): + if user.password and not user.password.startswith('$'): + user_list.append(user_tmpl_pass % (user.name, user.login, user.password)) + else: + user_list.append(user_tmpl_nopass % (user.name, user.login)) + return _('The following users have been installed : \n')+ '\n'.join(user_list) _columns = { 'installed_users':fields.text('Installed Users', readonly=True), === modified file 'document_ftp/test_easyftp.py' --- document_ftp/test_easyftp.py 2011-01-11 11:03:57 +0000 +++ document_ftp/test_easyftp.py 2011-01-11 15:51:39 +0000 @@ -37,7 +37,16 @@ def get_ftp_login(cr, uid, ormobj): ftp = get_plain_ftp() user = ormobj.pool.get('res.users').read(cr, uid, uid) +<<<<<<< TREE ftp.login(user.get('login',''), user.get('login','')) +======= + passwd = user.get('password','') + if passwd.startswith("$1$"): + # md5 by base crypt. We cannot decode, wild guess + # that passwd = login + passwd = user.get('login', '') + ftp.login(user.get('login',''), passwd) +>>>>>>> MERGE-SOURCE ftp.cwd("/" + cr.dbname) return ftp === modified file 'document_webdav/test_davclient.py' --- document_webdav/test_davclient.py 2010-12-07 13:39:47 +0000 +++ document_webdav/test_davclient.py 2011-01-11 15:51:39 +0000 @@ -365,6 +365,10 @@ assert res, "uid %s not found" % uid self.user = res[0]['login'] self.passwd = res[0]['password'] + if self.passwd.startswith('$1$'): + # md5 by base crypt. We cannot decode, wild guess + # that passwd = login + self.passwd = self.user return True def set_useragent(self, uastr):
_______________________________________________ Mailing list: https://launchpad.net/~openerp-dev-gtk Post to : [email protected] Unsubscribe : https://launchpad.net/~openerp-dev-gtk More help : https://help.launchpad.net/ListHelp

