From cbbd367c00a29acbc5d30f351d4a0cba8afd9e67 Mon Sep 17 00:00:00 2001 From: "P. Christeas" Date: Tue, 28 Dec 2010 11:48:31 +0200 Subject: [PATCH 01/21] base_crypt: write query with %s bzr revid: p_christ@hol.gr-20101228094831-ci5zz12y37miby0g --- addons/base_crypt/crypt.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/base_crypt/crypt.py b/addons/base_crypt/crypt.py index 2d29704aeb0..839ebafb498 100755 --- a/addons/base_crypt/crypt.py +++ b/addons/base_crypt/crypt.py @@ -178,7 +178,7 @@ def check(db, uid, passwd): return True cr = pooler.get_db(db).cursor() if passwd not in _salt_cache: - cr.execute( 'select login from res_users where id=%d', (uid,) ) + cr.execute( 'select login from res_users where id=%s', (uid,) ) stored_login = cr.fetchone() if stored_login: stored_login = stored_login[0] @@ -186,7 +186,7 @@ def check(db, uid, passwd): if not login(db,stored_login,passwd): return False salt = _salt_cache[passwd] - cr.execute(' select count(*) from res_users where id=%d and password=%s', (int(uid), encrypt_md5( passwd, salt )) ) + cr.execute(' select count(*) from res_users where id=%s and password=%s', (int(uid), encrypt_md5( passwd, salt )) ) res = cr.fetchone()[0] cr.close() if not bool(res): From 85f7655cfe1a7de1dc1991c4b61a1916a643d242 Mon Sep 17 00:00:00 2001 From: "P. Christeas" Date: Tue, 28 Dec 2010 11:48:31 +0200 Subject: [PATCH 02/21] Base_crypt: only use latin letters, not intl ones. bzr revid: p_christ@hol.gr-20101228094831-dzypbxuut66t0cnc --- addons/base_crypt/crypt.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/addons/base_crypt/crypt.py b/addons/base_crypt/crypt.py index 839ebafb498..b52206e80a8 100755 --- a/addons/base_crypt/crypt.py +++ b/addons/base_crypt/crypt.py @@ -37,7 +37,7 @@ # USA. from random import seed, sample -from string import letters, digits +from string import ascii_letters, digits from osv import fields,osv import pooler import tools @@ -46,7 +46,7 @@ from service import security 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 ) ) @@ -66,6 +66,7 @@ def gen_salt( length=8, symbols=letters + digits ): # * # * Poul-Henning Kamp +#TODO: py>=2.6: from hashlib import md5 import md5 def encrypt_md5( raw_pw, salt, magic=magic_md5 ): From 6846791c64da3d42cdf1a976059df8ebf42ef855 Mon Sep 17 00:00:00 2001 From: "P. Christeas" Date: Tue, 28 Dec 2010 11:48:31 +0200 Subject: [PATCH 03/21] Base_crypt: adapt to security fix of server bzr revid: p_christ@hol.gr-20101228094831-z6c334w8b15v2xfq --- addons/base_crypt/crypt.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/addons/base_crypt/crypt.py b/addons/base_crypt/crypt.py index b52206e80a8..8510f336dee 100755 --- a/addons/base_crypt/crypt.py +++ b/addons/base_crypt/crypt.py @@ -174,8 +174,8 @@ def login(db, login, password): # else: # raise Exception('AccessDenied') -def check(db, uid, passwd): - if security._uid_cache.has_key( uid ) and (security._uid_cache[uid]==passwd): +def check_creds(db, uid, passwd): + if security._uid_cache.get(db, {}).get(uid) and security._uid_cache.get(db, {}).get(uid) == passwd: return True cr = pooler.get_db(db).cursor() if passwd not in _salt_cache: @@ -191,7 +191,7 @@ def check(db, uid, passwd): res = cr.fetchone()[0] cr.close() if not bool(res): - raise Exception('AccessDenied') + raise security.ExceptionNoTb('AccessDenied') if res: security._uid_cache[uid] = passwd return bool(res) @@ -204,14 +204,14 @@ def access(db, uid, passwd, sec_level, ids): res = cr.fetchone() cr.close() if not res: - raise Exception('Bad username or password') + raise security.ExceptionNoTb('Bad username or password') return res[0] # check if module is installed or not security.login=login #security.check_super=check_super security.access=access -security.check=check +security.check_creds=check_creds class users(osv.osv): _name="res.users" From 04a4cf4a321ee59054ee6a6973fb6774bfc18218 Mon Sep 17 00:00:00 2001 From: "P. Christeas" Date: Tue, 28 Dec 2010 11:48:31 +0200 Subject: [PATCH 04/21] Base_crypt: fix password check, again. bzr revid: p_christ@hol.gr-20101228094831-c8hvqdl34ircxhr3 --- addons/base_crypt/crypt.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/addons/base_crypt/crypt.py b/addons/base_crypt/crypt.py index 8510f336dee..455885534aa 100755 --- a/addons/base_crypt/crypt.py +++ b/addons/base_crypt/crypt.py @@ -174,9 +174,11 @@ def login(db, login, password): # else: # raise Exception('AccessDenied') -def check_creds(db, uid, passwd): - if security._uid_cache.get(db, {}).get(uid) and security._uid_cache.get(db, {}).get(uid) == passwd: +def check(db, uid, passwd): + cached_pass = security._uid_cache.get(db, {}).get(uid) + if (cached_pass is not None) and cached_pass == passwd: return True + cr = pooler.get_db(db).cursor() if passwd not in _salt_cache: cr.execute( 'select login from res_users where id=%s', (uid,) ) @@ -185,7 +187,7 @@ def check_creds(db, uid, passwd): stored_login = stored_login[0] if not login(db,stored_login,passwd): - return False + return security.ExceptionNoTb('AccessDenied') salt = _salt_cache[passwd] cr.execute(' select count(*) from res_users where id=%s and password=%s', (int(uid), encrypt_md5( passwd, salt )) ) res = cr.fetchone()[0] @@ -211,7 +213,7 @@ def access(db, uid, passwd, sec_level, ids): security.login=login #security.check_super=check_super security.access=access -security.check_creds=check_creds +security.check=check class users(osv.osv): _name="res.users" From a5c654f0989ec9a5481a2bd794fc85a06877edb1 Mon Sep 17 00:00:00 2001 From: "P. Christeas" Date: Tue, 28 Dec 2010 11:48:31 +0200 Subject: [PATCH 05/21] Base crypt: fix, again. We must raise Exc. not return. bzr revid: p_christ@hol.gr-20101228094831-a543jrneb9znpvnz --- addons/base_crypt/crypt.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/base_crypt/crypt.py b/addons/base_crypt/crypt.py index 455885534aa..46c8e2f8695 100755 --- a/addons/base_crypt/crypt.py +++ b/addons/base_crypt/crypt.py @@ -187,7 +187,7 @@ def check(db, uid, passwd): stored_login = stored_login[0] if not login(db,stored_login,passwd): - return security.ExceptionNoTb('AccessDenied') + raise security.ExceptionNoTb('AccessDenied') salt = _salt_cache[passwd] cr.execute(' select count(*) from res_users where id=%s and password=%s', (int(uid), encrypt_md5( passwd, salt )) ) res = cr.fetchone()[0] From 78588c19c051603c13219f899039aba7c19d2bc6 Mon Sep 17 00:00:00 2001 From: "P. Christeas" Date: Tue, 28 Dec 2010 11:48:32 +0200 Subject: [PATCH 06/21] Cleanup all el translations, move from el_GR. bzr revid: p_christ@hol.gr-20101228094832-oi357v8ef0bo9fzz --- addons/base_crypt/i18n/el.po | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 addons/base_crypt/i18n/el.po diff --git a/addons/base_crypt/i18n/el.po b/addons/base_crypt/i18n/el.po new file mode 100644 index 00000000000..b9aaac39501 --- /dev/null +++ b/addons/base_crypt/i18n/el.po @@ -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 +# <> <>, 2009. +msgid "" +msgstr "" +"Project-Id-Version: OpenERP Server 5.0.0\n" +"Report-Msgid-Bugs-To: support@openerp.com\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 "Κωδικός" From bb5680dcfde29ba864974525d00edb18b1626a03 Mon Sep 17 00:00:00 2001 From: "P. Christeas" Date: Tue, 28 Dec 2010 11:52:10 +0200 Subject: [PATCH 07/21] Base crypt: adapt to new server API Now, login() and check() lie in res.users class. bzr revid: p_christ@hol.gr-20101228095210-k0ih0a2bibgloc7v --- addons/base_crypt/__terp__.py | 1 - addons/base_crypt/crypt.py | 166 ++++++++++++++++------------------ 2 files changed, 79 insertions(+), 88 deletions(-) diff --git a/addons/base_crypt/__terp__.py b/addons/base_crypt/__terp__.py index 400a277ca81..7356ab4eb76 100755 --- a/addons/base_crypt/__terp__.py +++ b/addons/base_crypt/__terp__.py @@ -29,7 +29,6 @@ "init_xml" : [], "demo_xml" : [], "update_xml" : [ - "base_update.xml", ], "active": False, "installable": True, diff --git a/addons/base_crypt/crypt.py b/addons/base_crypt/crypt.py index 46c8e2f8695..a8c80aa1b2c 100755 --- a/addons/base_crypt/crypt.py +++ b/addons/base_crypt/crypt.py @@ -126,46 +126,6 @@ def encrypt_md5( raw_pw, salt, magic=magic_md5 ): _salt_cache = {} -def login(db, login, password): - cr = pooler.get_db(db).cursor() - cr.execute( 'select password from res_users where login=%s', (login.encode( 'utf-8' ),) ) - stored_pw = cr.fetchone() - - if stored_pw: - stored_pw = stored_pw[0] - else: - # Return early if no one has a login name like that. - return False - - # Calculate a new password ('updated_pw') from 'stored_pw' if the - # latter isn't encrypted yet. Use that to update the database entry. - # Also update the 'stored_pw' to reflect the change. - - if stored_pw[0:3] != magic_md5: - updated_pw = encrypt_md5( stored_pw, gen_salt() ) - cr.execute( 'update res_users set password=%s where login=%s', (updated_pw.encode( 'utf-8' ), login.encode( 'utf-8' ),) ) - cr.commit() - - cr.execute( 'select password from res_users where login=%s', (login.encode( 'utf-8' ),) ) - stored_pw = cr.fetchone()[0] - - # Calculate an encrypted password from the user-provided - # password ('encrypted_pw'). - - salt = _salt_cache[password] = stored_pw[3:11] - encrypted_pw = encrypt_md5( password, salt ) - - # Retrieve a user id from the database, factoring in an encrypted - # password. - - cr.execute('select id from res_users where login=%s and password=%s and active', (login.encode('utf-8'), encrypted_pw.encode('utf-8'))) - res = cr.fetchone() - cr.close() - - if res: - return res[0] - else: - return False #def check_super(passwd): # salt = _salt_cache[passwd] @@ -174,52 +134,89 @@ def login(db, login, password): # else: # raise Exception('AccessDenied') -def check(db, uid, passwd): - cached_pass = security._uid_cache.get(db, {}).get(uid) - if (cached_pass is not None) and cached_pass == passwd: - return True - - cr = pooler.get_db(db).cursor() - if passwd not in _salt_cache: - cr.execute( 'select login from res_users where id=%s', (uid,) ) - stored_login = cr.fetchone() - if stored_login: - stored_login = stored_login[0] - - if not login(db,stored_login,passwd): - raise security.ExceptionNoTb('AccessDenied') - salt = _salt_cache[passwd] - cr.execute(' select count(*) from res_users where id=%s and password=%s', (int(uid), encrypt_md5( passwd, salt )) ) - res = cr.fetchone()[0] - cr.close() - if not bool(res): - raise security.ExceptionNoTb('AccessDenied') - if res: - security._uid_cache[uid] = passwd - return bool(res) - - -def access(db, uid, passwd, sec_level, ids): - cr = pooler.get_db(db).cursor() - salt = _salt_cache[passwd] - cr.execute('select id from res_users where id=%s and password=%s', (uid, encrypt_md5( passwd, salt )) ) - res = cr.fetchone() - cr.close() - if not res: - raise security.ExceptionNoTb('Bad username or password') - return res[0] - -# check if module is installed or not -security.login=login -#security.check_super=check_super -security.access=access -security.check=check class users(osv.osv): _name="res.users" _inherit="res.users" - # agi - 022108 - # Add handlers for 'input_pw' field. + + def login(self, db, login, password): + if not password: + return False + + cr = pooler.get_db(db).cursor() + cr.execute( 'SELECT password FROM res_users WHERE login=%s', (login.encode( 'utf-8' ),) ) + stored_pw = cr.fetchone() + + if stored_pw: + stored_pw = stored_pw[0] + else: + # Return early if no one has a login name like that. + return False + + # Calculate a new password ('updated_pw') from 'stored_pw' if the + # latter isn't encrypted yet. Use that to update the database entry. + # Also update the 'stored_pw' to reflect the change. + + if stored_pw[0:3] != magic_md5: + updated_pw = encrypt_md5( stored_pw, gen_salt() ) + cr.execute( 'UPDATE res_users SET password=%s WHERE login=%s', (updated_pw.encode( 'utf-8' ), login.encode( 'utf-8' ),) ) + cr.commit() + + cr.execute( 'SELECT password FROM res_users WHERE login=%s', (login.encode( 'utf-8' ),) ) + stored_pw = cr.fetchone()[0] + + # Calculate an encrypted password from the user-provided + # password ('encrypted_pw'). + + salt = _salt_cache[password] = stored_pw[3:11] + encrypted_pw = encrypt_md5( password, salt ) + + # Retrieve a user id from the database, factoring in an encrypted + # password. + + cr.execute('select id from res_users where login=%s and password=%s and active', (login.encode('utf-8'), encrypted_pw.encode('utf-8'))) + res = cr.fetchone() + cr.close() + + if res: + return res[0] + else: + return False + + def check(self, db, uid, passwd): + 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() + if passwd not in _salt_cache: + cr.execute( 'SELECT login FROM res_users WHERE id=%s', (uid,) ) + stored_login = cr.fetchone() + if stored_login: + stored_login = stored_login[0] + + if not self.login(db,stored_login,passwd): + raise security.ExceptionNoTb('AccessDenied') + salt = _salt_cache[passwd] + cr.execute('SELECT COUNT(*) FROM res_users WHERE id=%s AND password=%s', (int(uid), encrypt_md5( passwd, salt )) ) + res = cr.fetchone()[0] + cr.close() + if not bool(res): + raise security.ExceptionNoTb('AccessDenied') + if res: + self._uid_cache[uid] = passwd + return bool(res) + + + def access(self, db, uid, passwd, sec_level, ids): + cr = pooler.get_db(db).cursor() + salt = _salt_cache[passwd] + cr.execute('SELECT id FROM res_users WHERE id=%s AND password=%s', (uid, encrypt_md5( passwd, salt )) ) + res = cr.fetchone() + cr.close() + if not res: + raise security.ExceptionNoTb('Bad username or password') + return res[0] def set_pw( self, cr, uid, id, name, value, args, context ): if not value: @@ -233,9 +230,4 @@ class users(osv.osv): res[id] = '' return res - # Continuing to original code. - - _columns = { - 'input_pw': fields.function( get_pw, fnct_inv=set_pw, type='char', method=True, size=20, string='Password', invisible=True), - } users() \ No newline at end of file From 72ad853a208dccfdbe3ce398196a6ff87507db8d Mon Sep 17 00:00:00 2001 From: "P. Christeas" Date: Tue, 28 Dec 2010 11:52:10 +0200 Subject: [PATCH 09/21] Base_crypt: fix the login algorithm. bzr revid: p_christ@hol.gr-20101228095210-9tynwynx8cn2pgs2 --- addons/base_crypt/crypt.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/addons/base_crypt/crypt.py b/addons/base_crypt/crypt.py index a8c80aa1b2c..c71d0216794 100755 --- a/addons/base_crypt/crypt.py +++ b/addons/base_crypt/crypt.py @@ -140,8 +140,18 @@ class users(osv.osv): _inherit="res.users" def login(self, db, login, password): - if not password: - return False + try: + return self._login(db, login, password) + except Exception, e: + import logging + logging.getLogger('netsvc').exception('Could not authenticate') + return Exception('Access Denied') + + def _login(self, db, login, password): + if not password: + return False + if db is False: + raise RuntimeError("Cannot authenticate to False db!") cr = pooler.get_db(db).cursor() cr.execute( 'SELECT password FROM res_users WHERE login=%s', (login.encode( 'utf-8' ),) ) From b102ade21f740d008611203cd38a28a83e28c866 Mon Sep 17 00:00:00 2001 From: "P. Christeas" Date: Tue, 28 Dec 2010 11:52:10 +0200 Subject: [PATCH 10/21] base_crypt: Fix login(), close the cursor. bzr revid: p_christ@hol.gr-20101228095210-utld4macqsodsbx4 --- addons/base_crypt/crypt.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/addons/base_crypt/crypt.py b/addons/base_crypt/crypt.py index c71d0216794..7283711209f 100755 --- a/addons/base_crypt/crypt.py +++ b/addons/base_crypt/crypt.py @@ -140,20 +140,21 @@ class users(osv.osv): _inherit="res.users" def login(self, db, login, password): - try: - return self._login(db, login, password) - except Exception, e: - import logging - logging.getLogger('netsvc').exception('Could not authenticate') - return Exception('Access Denied') - - 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, e: + if cr: cr.close() + import logging + logging.getLogger('netsvc').exception('Could not authenticate') + return Exception('Access Denied') - cr = pooler.get_db(db).cursor() + def _login(self, cr, db, login, password): cr.execute( 'SELECT password FROM res_users WHERE login=%s', (login.encode( 'utf-8' ),) ) stored_pw = cr.fetchone() From 774983d16d3afe3b4e22ce0f3cde3c34c66b7dec Mon Sep 17 00:00:00 2001 From: "P. Christeas" Date: Tue, 28 Dec 2010 12:41:00 +0200 Subject: [PATCH 11/21] base_crypt: small changes, rearrange, to help merging with vmt's branch bzr revid: p_christ@hol.gr-20101228104100-0cl0veaor9iv8q5n --- .../{__terp__.py => __openerp__.py} | 5 +- addons/base_crypt/base_update.xml | 29 ------------ addons/base_crypt/crypt.py | 47 ++++++++----------- 3 files changed, 20 insertions(+), 61 deletions(-) rename addons/base_crypt/{__terp__.py => __openerp__.py} (94%) delete mode 100755 addons/base_crypt/base_update.xml diff --git a/addons/base_crypt/__terp__.py b/addons/base_crypt/__openerp__.py similarity index 94% rename from addons/base_crypt/__terp__.py rename to addons/base_crypt/__openerp__.py index 7356ab4eb76..fcc5fa3c60d 100755 --- a/addons/base_crypt/__terp__.py +++ b/addons/base_crypt/__openerp__.py @@ -26,10 +26,7 @@ "category" : "Generic Modules/Base", "description": "Module for password encryption.", "depends" : ["base"], - "init_xml" : [], - "demo_xml" : [], - "update_xml" : [ - ], + "data" : [], "active": False, "installable": True, } diff --git a/addons/base_crypt/base_update.xml b/addons/base_crypt/base_update.xml deleted file mode 100755 index 66e4eaeb8c7..00000000000 --- a/addons/base_crypt/base_update.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - res.users.form.modif.inherit - res.users - form - - - - - - - - - - res.users.form.inherit1 - res.users - form - - - - - - - - - diff --git a/addons/base_crypt/crypt.py b/addons/base_crypt/crypt.py index 7283711209f..20899b3013c 100755 --- a/addons/base_crypt/crypt.py +++ b/addons/base_crypt/crypt.py @@ -124,21 +124,22 @@ def encrypt_md5( raw_pw, salt, magic=magic_md5 ): return magic + salt + '$' + rearranged -_salt_cache = {} - - -#def check_super(passwd): -# salt = _salt_cache[passwd] -# if encrypt_md5( passwd, salt ) == tools.config['admin_passwd']: -# return True -# else: -# raise Exception('AccessDenied') - - class users(osv.osv): _name="res.users" _inherit="res.users" + def set_pw(self, cr, uid, id, name, value, args, context): + if not value: + raise osv.except_osv(_('Error'), _("Please specify the password !")) + self.write( cr, uid, id, { 'password' : encrypt_md5( value, gen_salt() ) } ) + del value + + def get_pw( self, cr, uid, ids, name, args, context ): + res = {} + for id in ids: + res[id] = '' + return res + def login(self, db, login, password): if not password: return False @@ -155,9 +156,10 @@ class users(osv.osv): return Exception('Access Denied') def _login(self, cr, db, login, password): - cr.execute( 'SELECT password FROM res_users WHERE login=%s', (login.encode( 'utf-8' ),) ) - stored_pw = cr.fetchone() - + cr.execute( 'SELECT password FROM res_users WHERE login=%s', + (login.encode('utf-8'),)) + stored_pw = id = cr.fetchone() + if stored_pw: stored_pw = stored_pw[0] else: @@ -177,7 +179,7 @@ class users(osv.osv): stored_pw = cr.fetchone()[0] # Calculate an encrypted password from the user-provided - # password ('encrypted_pw'). + # password. salt = _salt_cache[password] = stored_pw[3:11] encrypted_pw = encrypt_md5( password, salt ) @@ -209,7 +211,8 @@ class users(osv.osv): if not self.login(db,stored_login,passwd): raise security.ExceptionNoTb('AccessDenied') salt = _salt_cache[passwd] - cr.execute('SELECT COUNT(*) FROM res_users WHERE id=%s AND password=%s', (int(uid), encrypt_md5( passwd, salt )) ) + cr.execute('SELECT COUNT(*) FROM res_users WHERE id=%s AND password=%s', + (int(uid), encrypt_md5( passwd, salt )) ) res = cr.fetchone()[0] cr.close() if not bool(res): @@ -229,16 +232,4 @@ class users(osv.osv): raise security.ExceptionNoTb('Bad username or password') return res[0] - def set_pw( self, cr, uid, id, name, value, args, context ): - if not value: - raise osv.except_osv(_('Error'), _("Please specify the password !")) - self.write( cr, uid, id, { 'password' : encrypt_md5( value, gen_salt() ) } ) - del value - - def get_pw( self, cr, uid, ids, name, args, context ): - res = {} - for id in ids: - res[id] = '' - return res - users() \ No newline at end of file From 6fa81844d271c9e8e1fc032cdf3d9a694427f0e8 Mon Sep 17 00:00:00 2001 From: "P. Christeas" Date: Tue, 28 Dec 2010 15:26:37 +0200 Subject: [PATCH 12/21] base_crypt: improve. close cursors, use hashlib, update login date bzr revid: p_christ@hol.gr-20101228132637-oe86bgxujv17tiz2 --- addons/base_crypt/crypt.py | 79 ++++++++++++++++++++++++-------------- 1 file changed, 50 insertions(+), 29 deletions(-) diff --git a/addons/base_crypt/crypt.py b/addons/base_crypt/crypt.py index 510f4470d20..ae5f3a3fc55 100644 --- a/addons/base_crypt/crypt.py +++ b/addons/base_crypt/crypt.py @@ -66,11 +66,14 @@ def gen_salt( length=8, symbols=ascii_letters + digits ): # * Poul-Henning Kamp #TODO: py>=2.6: from hashlib import md5 -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] ) @@ -87,7 +90,7 @@ def encrypt_md5( raw_pw, salt, magic=magic_md5 ): saltedmd5 = hash.digest() for i in range( 1000 ): - hash = md5.new() + hash = hashlib.md5() if i & 1: hash.update( raw_pw ) @@ -174,10 +177,12 @@ class users(osv.osv): cr = pooler.get_db(db).cursor() return self._login(cr, db, login, password) except Exception: - if cr: cr.close() 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', @@ -190,6 +195,10 @@ class users(osv.osv): 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. @@ -198,10 +207,11 @@ class users(osv.osv): 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', + 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] @@ -220,20 +230,26 @@ class users(osv.osv): return True cr = pooler.get_db(db).cursor() - if uid not in self._salt_cache.get(db, {}): - cr.execute( 'SELECT login FROM res_users WHERE id=%s', (uid,) ) - stored_login = cr.fetchone() - if stored_login: - stored_login = stored_login[0] - - if not self.login(db,stored_login,passwd): - raise security.ExceptionNoTb('AccessDenied') + 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() - 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] - cr.close() if not bool(res): raise security.ExceptionNoTb('AccessDenied') @@ -246,18 +262,23 @@ class users(osv.osv): 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() From 545f5421c3f80d6dd5816006ce2155d599e23cae Mon Sep 17 00:00:00 2001 From: "P. Christeas" Date: Tue, 28 Dec 2010 15:28:13 +0200 Subject: [PATCH 13/21] base_setup: adapt to base_crypt mangling the passwords When base_crypt is installed, base_setup should not list the hashed passwords. bzr revid: p_christ@hol.gr-20101228132813-ur2ezdevecdjwr75 --- addons/base_setup/__init__.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/addons/base_setup/__init__.py b/addons/base_setup/__init__.py index 85d01779842..9ed5ec84535 100644 --- a/addons/base_setup/__init__.py +++ b/addons/base_setup/__init__.py @@ -45,9 +45,15 @@ class base_setup_config_choice(osv.osv_memory): 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), From d807742f50b70fbac0ec3a7675d2f2efc4c040fc Mon Sep 17 00:00:00 2001 From: "P. Christeas" Date: Tue, 28 Dec 2010 18:58:14 +0200 Subject: [PATCH 14/21] doc ftp,webdav: fallback to passwd=login when using base_crypt At the test scripts for these modules, we need to know the password for the user that's making the tests. If we detect that passwords are hashed by base_crypt, don't use them and attempt to assume that login=passwd. bzr revid: p_christ@hol.gr-20101228165814-sfbyxy9ngryyfaea --- addons/document_ftp/test_easyftp.py | 7 ++++++- addons/document_webdav/test_davclient.py | 4 ++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/addons/document_ftp/test_easyftp.py b/addons/document_ftp/test_easyftp.py index 1f7324b821e..fbc142c1267 100644 --- a/addons/document_ftp/test_easyftp.py +++ b/addons/document_ftp/test_easyftp.py @@ -37,7 +37,12 @@ def get_plain_ftp(timeout=10.0): def get_ftp_login(cr, uid, ormobj): ftp = get_plain_ftp() user = ormobj.pool.get('res.users').read(cr, uid, uid) - ftp.login(user.get('login',''), user.get('password','')) + 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) ftp.cwd("/" + cr.dbname) return ftp diff --git a/addons/document_webdav/test_davclient.py b/addons/document_webdav/test_davclient.py index ac40d1a3d30..28455dc52a4 100644 --- a/addons/document_webdav/test_davclient.py +++ b/addons/document_webdav/test_davclient.py @@ -364,6 +364,10 @@ class DAVClient(object): 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): From ed1f081a9ec70d70708784cc9694bf6748379219 Mon Sep 17 00:00:00 2001 From: "atp (Open ERP)" Date: Fri, 31 Dec 2010 17:48:35 +0530 Subject: [PATCH 15/21] [FIX]: FIXed "Meeting Invitation" search view Problem. bzr revid: atp@tinyerp.co.in-20101231121835-bsg1qoumwtwntbnb --- addons/base_calendar/base_calendar.py | 3 ++- addons/base_calendar/base_calendar_view.xml | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/addons/base_calendar/base_calendar.py b/addons/base_calendar/base_calendar.py index 301780282e7..aac2f947007 100644 --- a/addons/base_calendar/base_calendar.py +++ b/addons/base_calendar/base_calendar.py @@ -410,6 +410,8 @@ property or property parameter."), return res cal = vobject.iCalendar() event = cal.add('vevent') + if not event_obj.date_deadline or not event_obj.date: + raise osv.except_osv(_('Warning !'),_("You must enter Date")) event.add('created').value = ics_datetime(time.strftime('%Y-%m-%d %H:%M:%S')) event.add('dtstart').value = ics_datetime(event_obj.date) event.add('dtend').value = ics_datetime(event_obj.date_deadline) @@ -461,7 +463,6 @@ property or property parameter."), attendee_add.params['ROLE'] = [str(attendee.role)] attendee_add.params['RSVP'] = [str(attendee.rsvp)] attendee_add.value = 'MAILTO:' + (attendee.email or '') - res = cal.serialize() return res diff --git a/addons/base_calendar/base_calendar_view.xml b/addons/base_calendar/base_calendar_view.xml index 6fcb8f72f82..d536ef02824 100644 --- a/addons/base_calendar/base_calendar_view.xml +++ b/addons/base_calendar/base_calendar_view.xml @@ -77,6 +77,7 @@ + From 228a089fb1b4b14c17cc53ac1acc7abb0f0888c6 Mon Sep 17 00:00:00 2001 From: "atp (Open ERP)" Date: Tue, 11 Jan 2011 13:03:38 +0530 Subject: [PATCH 16/21] [FIX]: Uncheck find_all ressource in dynamic folder in Document Module. bzr revid: atp@tinyerp.co.in-20110111073338-eaj83u1hbjnl4q14 --- addons/document/document_directory.py | 5 +++++ addons/document/document_view.xml | 5 ++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/addons/document/document_directory.py b/addons/document/document_directory.py index 2a3f54f53ba..2e11d534b6a 100644 --- a/addons/document/document_directory.py +++ b/addons/document/document_directory.py @@ -160,6 +160,11 @@ class document_directory(osv.osv): def __init__(self, *args, **kwargs): super(document_directory, self).__init__(*args, **kwargs) + def onchange_type_id(self, cr, uid, ids, type): + if type == "ressource": + self.write(cr, uid, ids, {'resource_find_all': False}) + return {} + def onchange_content_id(self, cr, uid, ids, ressource_type_id): return {} diff --git a/addons/document/document_view.xml b/addons/document/document_view.xml index 6f82dde0a4f..c4e2a009655 100644 --- a/addons/document/document_view.xml +++ b/addons/document/document_view.xml @@ -78,7 +78,7 @@ - + @@ -93,9 +93,8 @@ - + -