From b495cec9d12666240ff4d8a31dc3ec0b97dcbcaf Mon Sep 17 00:00:00 2001 From: Husen Daudi Date: Wed, 28 May 2008 03:03:38 +0000 Subject: [PATCH 01/23] Module for password encryption. bzr revid: hda@tinyerp.com-20080528030338-7izwvtmmmizg9sp5 --- addons/base_crypt/__init__.py | 31 ++++++ addons/base_crypt/__terp__.py | 16 +++ addons/base_crypt/base_update.xml | 29 +++++ addons/base_crypt/crypt.py | 173 ++++++++++++++++++++++++++++++ 4 files changed, 249 insertions(+) create mode 100644 addons/base_crypt/__init__.py create mode 100644 addons/base_crypt/__terp__.py create mode 100644 addons/base_crypt/base_update.xml create mode 100644 addons/base_crypt/crypt.py diff --git a/addons/base_crypt/__init__.py b/addons/base_crypt/__init__.py new file mode 100644 index 00000000000..88854384b0e --- /dev/null +++ b/addons/base_crypt/__init__.py @@ -0,0 +1,31 @@ +############################################################################## +# +# Copyright (c) 2004 TINY SPRL. (http://tiny.be) All Rights Reserved. +# Fabien Pinckaers +# +# WARNING: This program as such is intended to be used by professional +# programmers who take the whole responsability 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 +# garantees 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. +# +############################################################################## + +from service import security +import crypt + diff --git a/addons/base_crypt/__terp__.py b/addons/base_crypt/__terp__.py new file mode 100644 index 00000000000..b6780541289 --- /dev/null +++ b/addons/base_crypt/__terp__.py @@ -0,0 +1,16 @@ +{ + "name" : "Base", + "version" : "1.0", + "author" : "Tiny", + "website" : "http://tinyerp.com", + "category" : "Generic Modules/Base", + "description": "Module for password encryption.", + "depends" : ["base"], + "init_xml" : [], + "demo_xml" : [], + "update_xml" : [ + "base_update.xml", + ], + "active": False, + "installable": True, +} diff --git a/addons/base_crypt/base_update.xml b/addons/base_crypt/base_update.xml new file mode 100644 index 00000000000..06de41b4850 --- /dev/null +++ b/addons/base_crypt/base_update.xml @@ -0,0 +1,29 @@ + + + + + + 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 new file mode 100644 index 00000000000..1d461463a27 --- /dev/null +++ b/addons/base_crypt/crypt.py @@ -0,0 +1,173 @@ +from random import seed, sample +from string import letters, digits +from osv import fields,osv +import pooler +import tools +from service import security + +magic_md5 = '$1$' + +def gen_salt( length=8, symbols=letters + digits ): + seed() + return ''.join( sample( symbols, length ) ) + +import md5 + +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() + + 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 = md5.new() + + 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 + +_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] +# if encrypt_md5( passwd, salt ) == tools.config['admin_passwd']: +# return True +# else: +# raise Exception('AccessDenied') + +def check(db, uid, passwd): + if security._uid_cache.has_key( uid ) and (security._uid_cache[uid]==passwd): + return True + cr = pooler.get_db(db).cursor() + salt = _salt_cache[passwd] + cr.execute(' select count(*) from res_users where id=%d and password=%s', (int(uid), encrypt_md5( passwd, salt )) ) + res = cr.fetchone()[0] + cr.close() + if not bool(res): + raise Exception('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 Exception('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 set_pw( self, cr, uid, id, name, value, args, context ): + 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 + + # 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 e830358b25b74430c8bceb3e724f774d440a09d1 Mon Sep 17 00:00:00 2001 From: Husen Daudi Date: Thu, 29 May 2008 04:46:07 +0000 Subject: [PATCH 02/23] Add copyrights bzr revid: hda@tinyerp.com-20080529044607-09pqwt6ihm3j62go --- addons/base_crypt/crypt.py | 54 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/addons/base_crypt/crypt.py b/addons/base_crypt/crypt.py index 1d461463a27..7d2ab0e8cf7 100644 --- a/addons/base_crypt/crypt.py +++ b/addons/base_crypt/crypt.py @@ -1,3 +1,41 @@ +# Notice: +# ------ +# +# 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. + from random import seed, sample from string import letters, digits from osv import fields,osv @@ -11,6 +49,22 @@ def gen_salt( length=8, symbols=letters + digits ): seed() return ''.join( sample( symbols, length ) ) +# The encrypt_md5 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 + import md5 def encrypt_md5( raw_pw, salt, magic=magic_md5 ): From 601f6d412b0e7f4c654b086632f0df9d0f4ca889 Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Thu, 29 May 2008 11:14:58 +0000 Subject: [PATCH 03/23] Changed author bzr revid: fp@tinyerp.com-20080529111458-x1rf2m3z134qs710 --- addons/base_crypt/__terp__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/base_crypt/__terp__.py b/addons/base_crypt/__terp__.py index b6780541289..8c93f4e9e01 100644 --- a/addons/base_crypt/__terp__.py +++ b/addons/base_crypt/__terp__.py @@ -1,7 +1,7 @@ { "name" : "Base", "version" : "1.0", - "author" : "Tiny", + "author" : "FS3 , Review Tiny", "website" : "http://tinyerp.com", "category" : "Generic Modules/Base", "description": "Module for password encryption.", From f522b775740cca110ae434e7b687d83501e6465c Mon Sep 17 00:00:00 2001 From: Husen Daudi Date: Wed, 11 Jun 2008 07:03:22 +0000 Subject: [PATCH 04/23] Improve code to check cache (reference: HMO) bzr revid: hda@tinyerp.com-20080611070322-smrboaciwsho7env --- addons/base_crypt/crypt.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/addons/base_crypt/crypt.py b/addons/base_crypt/crypt.py index 7d2ab0e8cf7..c3d7a71e5ef 100644 --- a/addons/base_crypt/crypt.py +++ b/addons/base_crypt/crypt.py @@ -176,6 +176,14 @@ def check(db, uid, passwd): if security._uid_cache.has_key( uid ) and (security._uid_cache[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,) ) + stored_login = cr.fetchone() + if stored_login: + stored_login = stored_login[0] + + 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 )) ) res = cr.fetchone()[0] From eebf1d9860aefdd6933f0a3dbf19d764d5b1d9aa Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Mon, 22 Sep 2008 10:10:56 +0200 Subject: [PATCH 05/23] merge bzr revid: vmt@openerp.com-20080922081056-td14d6etaevzjbzm --- addons/base_crypt/base_update.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/base_crypt/base_update.xml b/addons/base_crypt/base_update.xml index 06de41b4850..8a0a5443eb8 100644 --- a/addons/base_crypt/base_update.xml +++ b/addons/base_crypt/base_update.xml @@ -1,5 +1,5 @@ - + @@ -26,4 +26,4 @@ - + From 055921341c897b1e909a05ccc7e5e10c19fdf01f Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Tue, 4 Nov 2008 17:22:16 +0100 Subject: [PATCH 06/23] merge bzr revid: vmt@openerp.com-20081104162216-vrbjrkewfuejwj3r --- addons/base_crypt/__init__.py | 33 +++++++++++++-------------------- addons/base_crypt/__terp__.py | 21 +++++++++++++++++++++ 2 files changed, 34 insertions(+), 20 deletions(-) diff --git a/addons/base_crypt/__init__.py b/addons/base_crypt/__init__.py index 88854384b0e..db124dc453f 100644 --- a/addons/base_crypt/__init__.py +++ b/addons/base_crypt/__init__.py @@ -1,28 +1,21 @@ ############################################################################## # -# Copyright (c) 2004 TINY SPRL. (http://tiny.be) All Rights Reserved. -# Fabien Pinckaers +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2008 Tiny SPRL (). All Rights Reserved +# $Id$ # -# WARNING: This program as such is intended to be used by professional -# programmers who take the whole responsability 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 -# garantees 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 3 of the License, or +# (at your option) any later version. # -# 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. # -# 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. +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . # ############################################################################## diff --git a/addons/base_crypt/__terp__.py b/addons/base_crypt/__terp__.py index 8c93f4e9e01..8779f7381ee 100644 --- a/addons/base_crypt/__terp__.py +++ b/addons/base_crypt/__terp__.py @@ -1,3 +1,24 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2008 Tiny SPRL (). All Rights Reserved +# $Id$ +# +# 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 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +############################################################################## { "name" : "Base", "version" : "1.0", From 062c792152b62c4f7190bea58f221df500d49615 Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Thu, 19 Feb 2009 19:51:09 +0100 Subject: [PATCH 07/23] merge bzr revid: vmt@openerp.com-20090219185109-qlyshbp6av7njujp --- addons/base_crypt/__terp__.py | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/addons/base_crypt/__terp__.py b/addons/base_crypt/__terp__.py index 8779f7381ee..6a3164f9aec 100644 --- a/addons/base_crypt/__terp__.py +++ b/addons/base_crypt/__terp__.py @@ -20,18 +20,18 @@ # ############################################################################## { - "name" : "Base", - "version" : "1.0", - "author" : "FS3 , Review Tiny", - "website" : "http://tinyerp.com", - "category" : "Generic Modules/Base", - "description": "Module for password encryption.", - "depends" : ["base"], - "init_xml" : [], - "demo_xml" : [], - "update_xml" : [ - "base_update.xml", - ], - "active": False, - "installable": True, + "name" : "Base", + "version" : "1.0", + "author" : "FS3 , Review Tiny", + "website" : "http://www.openerp.com", + "category" : "Generic Modules/Base", + "description": "Module for password encryption.", + "depends" : ["base"], + "init_xml" : [], + "demo_xml" : [], + "update_xml" : [ + "base_update.xml", + ], + "active": False, + "installable": True, } From ccfe97090b321a39f82a2d6b76f9ad10152d68f4 Mon Sep 17 00:00:00 2001 From: Mantavya Gajjar Date: Thu, 15 Oct 2009 19:27:18 +0530 Subject: [PATCH 08/23] [MERGE]:merging from the same branch bzr revid: vmt@openerp.com-20091015135718-cr715tqqm9ub6amz --- addons/base_crypt/__init__.py | 19 +++++++++---------- addons/base_crypt/__terp__.py | 19 +++++++++---------- 2 files changed, 18 insertions(+), 20 deletions(-) diff --git a/addons/base_crypt/__init__.py b/addons/base_crypt/__init__.py index db124dc453f..a8b9a6b0740 100644 --- a/addons/base_crypt/__init__.py +++ b/addons/base_crypt/__init__.py @@ -1,21 +1,20 @@ ############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2004-2008 Tiny SPRL (). All Rights Reserved -# $Id$ +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2009 Tiny SPRL (). # # 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 3 of the License, or -# (at your option) any later version. +# 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 General Public License for more details. +# GNU Affero General Public License for more details. # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . # ############################################################################## diff --git a/addons/base_crypt/__terp__.py b/addons/base_crypt/__terp__.py index 6a3164f9aec..c8454fff0cc 100644 --- a/addons/base_crypt/__terp__.py +++ b/addons/base_crypt/__terp__.py @@ -1,22 +1,21 @@ # -*- encoding: utf-8 -*- ############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2004-2008 Tiny SPRL (). All Rights Reserved -# $Id$ +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2009 Tiny SPRL (). # # 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 3 of the License, or -# (at your option) any later version. +# 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 General Public License for more details. +# GNU Affero General Public License for more details. # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . # ############################################################################## { From 7e098c3fa9b88b8a22e945dc5b810a2758322fc4 Mon Sep 17 00:00:00 2001 From: Mantavya Gajjar Date: Wed, 25 Nov 2009 15:20:36 +0530 Subject: [PATCH 09/23] [MERGE]: merging from the same branch bzr revid: vmt@openerp.com-20091125095036-klz8sos8eey5urnp --- addons/base_crypt/__terp__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/base_crypt/__terp__.py b/addons/base_crypt/__terp__.py index c8454fff0cc..400a277ca81 100644 --- a/addons/base_crypt/__terp__.py +++ b/addons/base_crypt/__terp__.py @@ -19,7 +19,7 @@ # ############################################################################## { - "name" : "Base", + "name" : "Base - Password Encryption", "version" : "1.0", "author" : "FS3 , Review Tiny", "website" : "http://www.openerp.com", From 0232413678ff45f8b3beee4e026204898920fae2 Mon Sep 17 00:00:00 2001 From: Mantavya Gajjar Date: Wed, 25 Nov 2009 19:44:35 +0530 Subject: [PATCH 10/23] [MERGE]: merging from same branch bzr revid: vmt@openerp.com-20091125141435-vsxil5iy8pa69jgj --- addons/base_crypt/crypt.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/addons/base_crypt/crypt.py b/addons/base_crypt/crypt.py index c3d7a71e5ef..2d29704aeb0 100644 --- a/addons/base_crypt/crypt.py +++ b/addons/base_crypt/crypt.py @@ -41,6 +41,7 @@ from string import letters, digits from osv import fields,osv import pooler import tools +from tools.translate import _ from service import security magic_md5 = '$1$' @@ -218,6 +219,8 @@ class users(osv.osv): # Add handlers for 'input_pw' field. 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 From 0a3c2bf26d4f899aa1f18519e9f426f3f91d173c Mon Sep 17 00:00:00 2001 From: Mantavya Gajjar Date: Tue, 1 Dec 2009 15:49:51 +0530 Subject: [PATCH 11/23] [MERGE]: merging from same branch bzr revid: vmt@openerp.com-20091201101951-0gqnmboirjoelwly --- addons/base_crypt/i18n/fr_BE.po | 37 +++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 addons/base_crypt/i18n/fr_BE.po diff --git a/addons/base_crypt/i18n/fr_BE.po b/addons/base_crypt/i18n/fr_BE.po new file mode 100644 index 00000000000..d62691cb699 --- /dev/null +++ b/addons/base_crypt/i18n/fr_BE.po @@ -0,0 +1,37 @@ +# Translation of OpenERP Server. +# This file contains the translation of the following modules: +# * base_crypt +# +msgid "" +msgstr "" +"Project-Id-Version: OpenERP Server 5.0.6\n" +"Report-Msgid-Bugs-To: support@openerp.com\n" +"POT-Creation-Date: 2009-11-26 09:12:09+0000\n" +"PO-Revision-Date: 2009-11-26 09:12:09+0000\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" + +#. module: base_crypt +#: model:ir.module.module,description:base_crypt.module_meta_information +msgid "Module for password encryption." +msgstr "" + +#. module: base_crypt +#: constraint:ir.ui.view:0 +msgid "Invalid XML for View Architecture!" +msgstr "" + +#. module: base_crypt +#: model:ir.module.module,shortdesc:base_crypt.module_meta_information +msgid "Base" +msgstr "" + +#. module: base_crypt +#: field:res.users,input_pw:0 +msgid "Password" +msgstr "" + From da1395bb41bdeeedee3cb26f06693d3beeb5fbc0 Mon Sep 17 00:00:00 2001 From: Mantavya Gajjar Date: Sun, 3 Jan 2010 00:41:50 +0530 Subject: [PATCH 12/23] [MERGE]: merging from same branch bzr revid: vmt@openerp.com-20100102191150-mnajl1zi8lxt776h --- addons/base_crypt/i18n/base_crypt.pot | 37 +++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 addons/base_crypt/i18n/base_crypt.pot diff --git a/addons/base_crypt/i18n/base_crypt.pot b/addons/base_crypt/i18n/base_crypt.pot new file mode 100644 index 00000000000..d62691cb699 --- /dev/null +++ b/addons/base_crypt/i18n/base_crypt.pot @@ -0,0 +1,37 @@ +# Translation of OpenERP Server. +# This file contains the translation of the following modules: +# * base_crypt +# +msgid "" +msgstr "" +"Project-Id-Version: OpenERP Server 5.0.6\n" +"Report-Msgid-Bugs-To: support@openerp.com\n" +"POT-Creation-Date: 2009-11-26 09:12:09+0000\n" +"PO-Revision-Date: 2009-11-26 09:12:09+0000\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" + +#. module: base_crypt +#: model:ir.module.module,description:base_crypt.module_meta_information +msgid "Module for password encryption." +msgstr "" + +#. module: base_crypt +#: constraint:ir.ui.view:0 +msgid "Invalid XML for View Architecture!" +msgstr "" + +#. module: base_crypt +#: model:ir.module.module,shortdesc:base_crypt.module_meta_information +msgid "Base" +msgstr "" + +#. module: base_crypt +#: field:res.users,input_pw:0 +msgid "Password" +msgstr "" + From 6f5ead9b97fc2f82a43f6bf0ad3e75d4865c24ad Mon Sep 17 00:00:00 2001 From: "sma (Tiny)" Date: Wed, 3 Mar 2010 17:52:02 +0530 Subject: [PATCH 13/23] [FIX] base_crypt: make password field hidden by setting password=True. lp bug: https://launchpad.net/bugs/530743 fixed bzr revid: sma@tinyerp.com-20100303122202-v512lrl8mep2uf0b --- addons/base_crypt/base_update.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/base_crypt/base_update.xml b/addons/base_crypt/base_update.xml index 8a0a5443eb8..66e4eaeb8c7 100644 --- a/addons/base_crypt/base_update.xml +++ b/addons/base_crypt/base_update.xml @@ -10,7 +10,7 @@ - + @@ -21,7 +21,7 @@ - + From 756ab060bb31d471da52ece6bbc6d21fd108d2ed Mon Sep 17 00:00:00 2001 From: "ksa (Open ERP)" Date: Tue, 6 Jul 2010 10:40:58 +0530 Subject: [PATCH 14/23] [IMP]:Remove print statement bzr revid: vmt@openerp.com-20100706051058-q29kpyy7s80i0e9h --- addons/base_crypt/__init__.py | 0 addons/base_crypt/__terp__.py | 0 addons/base_crypt/base_update.xml | 0 addons/base_crypt/crypt.py | 0 addons/base_crypt/i18n/base_crypt.pot | 0 addons/base_crypt/i18n/fr_BE.po | 0 6 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 addons/base_crypt/__init__.py mode change 100644 => 100755 addons/base_crypt/__terp__.py mode change 100644 => 100755 addons/base_crypt/base_update.xml mode change 100644 => 100755 addons/base_crypt/crypt.py mode change 100644 => 100755 addons/base_crypt/i18n/base_crypt.pot mode change 100644 => 100755 addons/base_crypt/i18n/fr_BE.po diff --git a/addons/base_crypt/__init__.py b/addons/base_crypt/__init__.py old mode 100644 new mode 100755 diff --git a/addons/base_crypt/__terp__.py b/addons/base_crypt/__terp__.py old mode 100644 new mode 100755 diff --git a/addons/base_crypt/base_update.xml b/addons/base_crypt/base_update.xml old mode 100644 new mode 100755 diff --git a/addons/base_crypt/crypt.py b/addons/base_crypt/crypt.py old mode 100644 new mode 100755 diff --git a/addons/base_crypt/i18n/base_crypt.pot b/addons/base_crypt/i18n/base_crypt.pot old mode 100644 new mode 100755 diff --git a/addons/base_crypt/i18n/fr_BE.po b/addons/base_crypt/i18n/fr_BE.po old mode 100644 new mode 100755 From 2eb478376b72f25d4e847e4e28a3ebca3b94cc3f Mon Sep 17 00:00:00 2001 From: Maxime Chambreuil Date: Tue, 14 Dec 2010 18:06:21 -0500 Subject: [PATCH 15/23] [MERGE] l10n_ca_toponyms bzr revid: vmt@openerp.com-20101214230621-uezqc251q92cbqdn --- addons/base_crypt/i18n/sv.po | 40 ++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 addons/base_crypt/i18n/sv.po diff --git a/addons/base_crypt/i18n/sv.po b/addons/base_crypt/i18n/sv.po new file mode 100644 index 00000000000..0901ea37990 --- /dev/null +++ b/addons/base_crypt/i18n/sv.po @@ -0,0 +1,40 @@ +# Translation of OpenERP Server. +# This file contains the translation of the following modules: +# * base_crypt +# +msgid "" +msgstr "" +"Project-Id-Version: OpenERP Server 5.0.14\n" +"Report-Msgid-Bugs-To: support@openerp.com\n" +"POT-Creation-Date: 2009-11-26 09:12+0000\n" +"PO-Revision-Date: 2010-11-23 02:16+0000\n" +"Last-Translator: Olivier Dony (OpenERP) \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2010-11-24 05:15+0000\n" +"X-Generator: Launchpad (build Unknown)\n" + +#. module: base_crypt +#: model:ir.module.module,description:base_crypt.module_meta_information +msgid "Module for password encryption." +msgstr "" + +#. module: base_crypt +#: constraint:ir.ui.view:0 +msgid "Invalid XML for View Architecture!" +msgstr "" + +#. module: base_crypt +#: model:ir.module.module,shortdesc:base_crypt.module_meta_information +msgid "Base" +msgstr "" + +#. module: base_crypt +#: field:res.users,input_pw:0 +msgid "Password" +msgstr "" + +#~ msgid "Module for password encryption.KKKKKKKKKKKKKKKKKKK" +#~ msgstr "Module for password encryption.KKKKKKKKKKKKKKKKKKK" From b7983627a6393418dc2f54fc2a093ffe5e1e47ec Mon Sep 17 00:00:00 2001 From: Launchpad Translations on behalf of openerp-commiter <> Date: Wed, 15 Dec 2010 05:44:29 +0000 Subject: [PATCH 16/23] Launchpad automatic translations update. bzr revid: vmt@openerp.com-20101215054429-wqs68zw7qwfs011s --- addons/base_crypt/i18n/sv.po | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/base_crypt/i18n/sv.po b/addons/base_crypt/i18n/sv.po index 0901ea37990..a20776a2100 100644 --- a/addons/base_crypt/i18n/sv.po +++ b/addons/base_crypt/i18n/sv.po @@ -13,7 +13,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2010-11-24 05:15+0000\n" +"X-Launchpad-Export-Date: 2010-12-15 05:38+0000\n" "X-Generator: Launchpad (build Unknown)\n" #. module: base_crypt From 0594c0c96face882c6b467807323275b87fd95aa Mon Sep 17 00:00:00 2001 From: Vo Minh Thu Date: Wed, 22 Dec 2010 17:18:41 +0100 Subject: [PATCH 17/23] [IMP] base_crypt: access, login, and check are now methods of the users class (changes for v6). bzr revid: vmt@openerp.com-20101222161841-lwgycpyq6c81vfv3 --- addons/base_crypt/crypt.py | 164 ++++++++++++++++++------------------- 1 file changed, 81 insertions(+), 83 deletions(-) diff --git a/addons/base_crypt/crypt.py b/addons/base_crypt/crypt.py index 2d29704aeb0..b6a6ea4e3c5 100755 --- a/addons/base_crypt/crypt.py +++ b/addons/base_crypt/crypt.py @@ -123,49 +123,6 @@ def encrypt_md5( raw_pw, salt, magic=magic_md5 ): return magic + salt + '$' + rearranged -_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] # if encrypt_md5( passwd, salt ) == tools.config['admin_passwd']: @@ -173,51 +130,14 @@ 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): - 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,) ) - stored_login = cr.fetchone() - if stored_login: - stored_login = stored_login[0] - - 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 )) ) - res = cr.fetchone()[0] - cr.close() - if not bool(res): - raise Exception('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 Exception('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. + _salt_cache = {} + def set_pw( self, cr, uid, id, name, value, args, context ): if not value: raise osv.except_osv(_('Error'), _("Please specify the password !")) @@ -235,4 +155,82 @@ class users(osv.osv): _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 + + def access(self, db, uid, passwd, sec_level, ids): + cr = pooler.get_db(db).cursor() + salt = self._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 Exception('Bad username or password') + return res[0] + + def login(self, 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. + + # TODO use length(magic_md5) instead of 3. + 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 = self._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): + # TODO see in self._uid_cache[db][uid] instead of + #if security._uid_cache.has_key( uid ) and (security._uid_cache[uid]==passwd): + # return True + cr = pooler.get_db(db).cursor() + if passwd not in self._salt_cache: + cr.execute( 'select login from res_users where id=%s', (int(uid),) ) + stored_login = cr.fetchone() + if stored_login: + stored_login = stored_login[0] + + if not login(db,stored_login,passwd): + return False + salt = self._salt_cache[passwd] + cr.execute(' select count(id) 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 Exception('AccessDenied') + # TODO see above + #if res: + # security._uid_cache[uid] = passwd + return bool(res) + +users() +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: From a0640060f525e4fdc1873d8d3ec9f434256ff3bc Mon Sep 17 00:00:00 2001 From: Vo Minh Thu Date: Thu, 23 Dec 2010 16:50:13 +0100 Subject: [PATCH 18/23] [IMP] base_crypt: uses the existing password column (making it a stored function field). bzr revid: vmt@openerp.com-20101223155013-20wd0vxgug1we02b --- .../{__terp__.py => __openerp__.py} | 6 +- addons/base_crypt/base_update.xml | 6 +- addons/base_crypt/crypt.py | 131 +++++++++++------- 3 files changed, 88 insertions(+), 55 deletions(-) rename addons/base_crypt/{__terp__.py => __openerp__.py} (93%) diff --git a/addons/base_crypt/__terp__.py b/addons/base_crypt/__openerp__.py similarity index 93% rename from addons/base_crypt/__terp__.py rename to addons/base_crypt/__openerp__.py index 400a277ca81..fcc5fa3c60d 100755 --- a/addons/base_crypt/__terp__.py +++ b/addons/base_crypt/__openerp__.py @@ -26,11 +26,7 @@ "category" : "Generic Modules/Base", "description": "Module for password encryption.", "depends" : ["base"], - "init_xml" : [], - "demo_xml" : [], - "update_xml" : [ - "base_update.xml", - ], + "data" : [], "active": False, "installable": True, } diff --git a/addons/base_crypt/base_update.xml b/addons/base_crypt/base_update.xml index 66e4eaeb8c7..2744053a61c 100755 --- a/addons/base_crypt/base_update.xml +++ b/addons/base_crypt/base_update.xml @@ -2,6 +2,8 @@ + + res.users.form.modif.inherit res.users @@ -10,7 +12,7 @@ - + @@ -21,7 +23,7 @@ - + diff --git a/addons/base_crypt/crypt.py b/addons/base_crypt/crypt.py index b6a6ea4e3c5..4c03442b9d0 100755 --- a/addons/base_crypt/crypt.py +++ b/addons/base_crypt/crypt.py @@ -123,43 +123,65 @@ def encrypt_md5( raw_pw, salt, magic=magic_md5 ): return magic + salt + '$' + rearranged -#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" # agi - 022108 # Add handlers for 'input_pw' field. + # Maps a res_users id to the salt used to encrypt its associated password. _salt_cache = {} - def set_pw( self, cr, uid, id, name, value, args, context ): + def set_pw(self, cr, uid, id, name, value, args, context): + print ">>>>>> set_pw %s" % str((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() ) } ) + + salt = self._salt_cache[id] = gen_salt() + encrypted = encrypt_md5(value, salt) + cr.execute('update res_users set password=%s where id=%s', + (encrypted.encode('utf-8'), id)) + cr.commit() del value def get_pw( self, cr, uid, ids, name, args, context ): + print ">>>>>> get_pw" + if len(ids) != 1: + # TODO multiple ids (and no id) + return {} + id = ids[0] + + cr.execute('select password from res_users where id=%s', (id,)) + stored_pw = cr.fetchone() + + if stored_pw: + stored_pw = stored_pw[0] + else: + # Return early if no such id. + return False + + stored_pw = self.maybe_encrypt_and_store(cr, stored_pw, id) + res = {} - for id in ids: - res[id] = '' + res[id] = stored_pw 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), - } + # The column size could be smaller as it is meant to store a hash, but + # an existing column cannot be downsized; thus we use the original + # column size. + 'password': fields.function(get_pw, fnct_inv=set_pw, type='char', + method=True, size=64, string='Password', invisible=True, + store=True), + } + # TODO This doesn't seem right: _salt_cache doesn't necessarily contain uid. def access(self, db, uid, passwd, sec_level, ids): + print ">>>>>> access" cr = pooler.get_db(db).cursor() - salt = self._salt_cache[passwd] - cr.execute('select id from res_users where id=%s and password=%s', (uid, encrypt_md5( passwd, salt )) ) + salt = self._salt_cache[uid] + 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: @@ -167,39 +189,28 @@ class users(osv.osv): return res[0] def login(self, db, login, password): + print ">>>>>> login" cr = pooler.get_db(db).cursor() - cr.execute( 'select password from res_users where login=%s', (login.encode( 'utf-8' ),) ) - stored_pw = cr.fetchone() + 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] else: - # Return early if no one has a login name like that. + # Return early if there is no such login. 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. - - # TODO use length(magic_md5) instead of 3. - 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] + stored_pw = self.maybe_encrypt_and_store(cr, stored_pw, id) # Calculate an encrypted password from the user-provided - # password ('encrypted_pw'). - - salt = self._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. + salt = self._salt_cache[id] = stored_pw[len(magic_md5):11] + encrypted_pw = encrypt_md5(password, salt) - cr.execute('select id from res_users where login=%s and password=%s and active', (login.encode('utf-8'), encrypted_pw.encode('utf-8'))) + # 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', (id, encrypted_pw.encode('utf-8'))) res = cr.fetchone() cr.close() @@ -209,28 +220,52 @@ class users(osv.osv): return False def check(self, db, uid, passwd): - # TODO see in self._uid_cache[db][uid] instead of - #if security._uid_cache.has_key( uid ) and (security._uid_cache[uid]==passwd): + print ">>>>>> check" + # TODO cannot use the cache as it would prevent the update by + # maybe_encrypt_and_store. + #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 self._salt_cache: - cr.execute( 'select login from res_users where id=%s', (int(uid),) ) + if uid not in self._salt_cache: + # TODO is int() useful ? + cr.execute('select login from res_users where id=%s', (int(uid),)) stored_login = cr.fetchone() if stored_login: stored_login = stored_login[0] - if not login(db,stored_login,passwd): + if not self.login(db,stored_login,passwd): return False - salt = self._salt_cache[passwd] - cr.execute(' select count(id) from res_users where id=%s and password=%s', (int(uid), encrypt_md5( passwd, salt )) ) + + salt = self._salt_cache[uid] + cr.execute('select count(id) 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 Exception('AccessDenied') - # TODO see above + #if res: - # security._uid_cache[uid] = passwd + # 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_and_store(self, cr, pw, id): + # Calculate a new password 'encrypted' from 'pw' if the + # latter isn't encrypted yet. Use it to update the database entry + # and return it, or simply return 'pw'. + + if pw[0:len(magic_md5)] != magic_md5: + encrypted = encrypt_md5(pw, gen_salt()) + cr.execute('update res_users set password=%s where id=%s', + (encrypted.encode('utf-8'), id)) + cr.commit() + return encrypted + return pw + users() # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: From e9c8d9ce770db7920fbf3393deeb01553ceb91ac Mon Sep 17 00:00:00 2001 From: Vo Minh Thu Date: Thu, 23 Dec 2010 17:31:00 +0100 Subject: [PATCH 19/23] [IMP] base_crypt: encrypting all passwords at the first check. bzr revid: vmt@openerp.com-20101223163100-ib3qf9i4kiqkpn77 --- addons/base_crypt/base_update.xml | 31 ------------------------------- addons/base_crypt/crypt.py | 29 ++++++++++++++++++----------- 2 files changed, 18 insertions(+), 42 deletions(-) delete mode 100755 addons/base_crypt/base_update.xml diff --git a/addons/base_crypt/base_update.xml b/addons/base_crypt/base_update.xml deleted file mode 100755 index 2744053a61c..00000000000 --- a/addons/base_crypt/base_update.xml +++ /dev/null @@ -1,31 +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 4c03442b9d0..3320cdf6ee0 100755 --- a/addons/base_crypt/crypt.py +++ b/addons/base_crypt/crypt.py @@ -160,7 +160,7 @@ class users(osv.osv): # Return early if no such id. return False - stored_pw = self.maybe_encrypt_and_store(cr, stored_pw, id) + stored_pw = self.maybe_encrypt(cr, stored_pw, id) res = {} res[id] = stored_pw @@ -202,7 +202,7 @@ class users(osv.osv): # Return early if there is no such login. return False - stored_pw = self.maybe_encrypt_and_store(cr, stored_pw, id) + stored_pw = self.maybe_encrypt(cr, stored_pw, id) # Calculate an encrypted password from the user-provided # password. @@ -222,7 +222,7 @@ class users(osv.osv): def check(self, db, uid, passwd): print ">>>>>> check" # TODO cannot use the cache as it would prevent the update by - # maybe_encrypt_and_store. + # maybe_encrypt. #cached_pass = self._uid_cache.get(db, {}).get(uid) #if (cached_pass is not None) and cached_pass == passwd: # return True @@ -254,17 +254,24 @@ class users(osv.osv): # self._uid_cache[db] = {uid: passwd} return bool(res) - def maybe_encrypt_and_store(self, cr, pw, id): - # Calculate a new password 'encrypted' from 'pw' if the - # latter isn't encrypted yet. Use it to update the database entry - # and return it, or simply return 'pw'. + 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'. if pw[0:len(magic_md5)] != magic_md5: - encrypted = encrypt_md5(pw, gen_salt()) - cr.execute('update res_users set password=%s where id=%s', - (encrypted.encode('utf-8'), id)) + cr.execute('select id, password from res_users') + res = cr.fetchall() + for i, p in res: + encrypted = p + if p[0:len(magic_md5)] != magic_md5: + encrypted = encrypt_md5(p, gen_salt()) + print ">>>>>> changing %s to %s" % (p, encrypted) + cr.execute('update res_users set password=%s where id=%s', + (encrypted.encode('utf-8'), i)) + if i == id: + encrypted_res = encrypted cr.commit() - return encrypted + return encrypted_res return pw users() From 911666b3625327d46afa8eeb6755470a7f3dcfef Mon Sep 17 00:00:00 2001 From: Vo Minh Thu Date: Sun, 26 Dec 2010 13:21:29 +0100 Subject: [PATCH 20/23] [IMP] base_crypt: use the uid_cache and only the login method makes sure all passwords are hashed. bzr revid: vmt@openerp.com-20101226122129-s3yqozd5822t3mfs --- addons/base_crypt/crypt.py | 76 +++++++++++++------------------------- 1 file changed, 25 insertions(+), 51 deletions(-) diff --git a/addons/base_crypt/crypt.py b/addons/base_crypt/crypt.py index 3320cdf6ee0..67621f98afe 100755 --- a/addons/base_crypt/crypt.py +++ b/addons/base_crypt/crypt.py @@ -131,39 +131,27 @@ class users(osv.osv): # Maps a res_users id to the salt used to encrypt its associated password. _salt_cache = {} + _clear_uid_cache = True def set_pw(self, cr, uid, id, name, value, args, context): - print ">>>>>> set_pw %s" % str((self, cr, uid, id, name, value, args, context)) if not value: raise osv.except_osv(_('Error'), _("Please specify the password !")) salt = self._salt_cache[id] = gen_salt() encrypted = encrypt_md5(value, salt) cr.execute('update res_users set password=%s where id=%s', - (encrypted.encode('utf-8'), id)) + (encrypted.encode('utf-8'), int(id))) cr.commit() del value def get_pw( self, cr, uid, ids, name, args, context ): - print ">>>>>> get_pw" - if len(ids) != 1: - # TODO multiple ids (and no id) - return {} - id = ids[0] - - cr.execute('select password from res_users where id=%s', (id,)) - stored_pw = cr.fetchone() - - if stored_pw: - stored_pw = stored_pw[0] - else: - # Return early if no such id. - return False - - stored_pw = self.maybe_encrypt(cr, stored_pw, id) - + cr.execute('select id, password from res_users where id in %s', (tuple(map(int, ids)),)) + stored_pws = cr.fetchall() res = {} - res[id] = stored_pw + + for id, stored_pw in stored_pws: + res[id] = stored_pw + return res _columns = { @@ -175,24 +163,10 @@ class users(osv.osv): store=True), } - # TODO This doesn't seem right: _salt_cache doesn't necessarily contain uid. - def access(self, db, uid, passwd, sec_level, ids): - print ">>>>>> access" - cr = pooler.get_db(db).cursor() - salt = self._salt_cache[uid] - 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 Exception('Bad username or password') - return res[0] - def login(self, db, login, password): - print ">>>>>> login" cr = pooler.get_db(db).cursor() cr.execute('select password, id from res_users where login=%s', - (login.encode( 'utf-8' ),)) + (login.encode('utf-8'),)) stored_pw = id = cr.fetchone() if stored_pw: @@ -210,7 +184,7 @@ 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', (id, encrypted_pw.encode('utf-8'))) + cr.execute('select id from res_users where id=%s and password=%s and active', (int(id), encrypted_pw.encode('utf-8'))) res = cr.fetchone() cr.close() @@ -220,16 +194,17 @@ class users(osv.osv): return False def check(self, db, uid, passwd): - print ">>>>>> check" - # TODO cannot use the cache as it would prevent the update by - # maybe_encrypt. - #cached_pass = self._uid_cache.get(db, {}).get(uid) - #if (cached_pass is not None) and cached_pass == passwd: - # return True + # Get a chance to hash all passwords in db before using the uid_cache. + if self._clear_uid_cache: + self._uid_cache.clear() + self._clear_uid_cache = False + + 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 uid not in self._salt_cache: - # TODO is int() useful ? cr.execute('select login from res_users where id=%s', (int(uid),)) stored_login = cr.fetchone() if stored_login: @@ -246,12 +221,12 @@ class users(osv.osv): if not bool(res): raise Exception('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} + 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): @@ -265,9 +240,8 @@ class users(osv.osv): encrypted = p if p[0:len(magic_md5)] != magic_md5: encrypted = encrypt_md5(p, gen_salt()) - print ">>>>>> changing %s to %s" % (p, encrypted) cr.execute('update res_users set password=%s where id=%s', - (encrypted.encode('utf-8'), i)) + (encrypted.encode('utf-8'), int(i))) if i == id: encrypted_res = encrypted cr.commit() From d3d48fd1518955279483d085467d82bef0b857d6 Mon Sep 17 00:00:00 2001 From: Vo Minh Thu Date: Mon, 27 Dec 2010 12:11:11 +0100 Subject: [PATCH 21/23] [IMP] base_crypt: make sure to also clear the salt cache. bzr revid: vmt@openerp.com-20101227111111-4xw1bkjij343jzpm --- addons/base_crypt/crypt.py | 1 + 1 file changed, 1 insertion(+) diff --git a/addons/base_crypt/crypt.py b/addons/base_crypt/crypt.py index 67621f98afe..3ae6aa0a74d 100755 --- a/addons/base_crypt/crypt.py +++ b/addons/base_crypt/crypt.py @@ -198,6 +198,7 @@ class users(osv.osv): if self._clear_uid_cache: self._uid_cache.clear() self._clear_uid_cache = False + self._salt_cache.clear() cached_pass = self._uid_cache.get(db, {}).get(uid) if (cached_pass is not None) and cached_pass == passwd: From 0e7f74342a2defe12594866f17f2b7a7cecf884a Mon Sep 17 00:00:00 2001 From: Vo Minh Thu Date: Mon, 27 Dec 2010 17:12:34 +0100 Subject: [PATCH 22/23] [IMP] base_crypt: caches are per db. bzr revid: vmt@openerp.com-20101227161234-kmg2gp1mvpav0qpb --- addons/base_crypt/crypt.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/addons/base_crypt/crypt.py b/addons/base_crypt/crypt.py index 3ae6aa0a74d..042a7567b1f 100755 --- a/addons/base_crypt/crypt.py +++ b/addons/base_crypt/crypt.py @@ -137,7 +137,8 @@ class users(osv.osv): if not value: raise osv.except_osv(_('Error'), _("Please specify the password !")) - salt = self._salt_cache[id] = gen_salt() + self._salt_cache.setdefault(cr.dbname, {}) + salt = self._salt_cache[cr.dbname][id] = gen_salt() encrypted = encrypt_md5(value, salt) cr.execute('update res_users set password=%s where id=%s', (encrypted.encode('utf-8'), int(id))) @@ -180,7 +181,8 @@ class users(osv.osv): # Calculate an encrypted password from the user-provided # password. - salt = self._salt_cache[id] = stored_pw[len(magic_md5):11] + self._salt_cache.setdefault(db, {}) + salt = self._salt_cache[db][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. @@ -196,16 +198,16 @@ class users(osv.osv): def check(self, db, uid, passwd): # Get a chance to hash all passwords in db before using the uid_cache. if self._clear_uid_cache: - self._uid_cache.clear() + self._uid_cache.get(db, {}).clear() self._clear_uid_cache = False - self._salt_cache.clear() + self._salt_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() - if uid not in self._salt_cache: + if uid not in self._salt_cache.get(db, {}): cr.execute('select login from res_users where id=%s', (int(uid),)) stored_login = cr.fetchone() if stored_login: @@ -214,7 +216,7 @@ class users(osv.osv): if not self.login(db,stored_login,passwd): return False - salt = self._salt_cache[uid] + salt = self._salt_cache[db][uid] cr.execute('select count(id) from res_users where id=%s and password=%s', (int(uid), encrypt_md5(passwd, salt))) res = cr.fetchone()[0] From fd845c7960aab1a8e1085531adea68f31186a403 Mon Sep 17 00:00:00 2001 From: Vo Minh Thu Date: Tue, 28 Dec 2010 15:27:40 +0100 Subject: [PATCH 23/23] [IMP] base_crypt: the salt cache is on the per db res.users object. bzr revid: vmt@openerp.com-20101228142740-qkhsrnyabjhgsdnx --- addons/base_crypt/crypt.py | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/addons/base_crypt/crypt.py b/addons/base_crypt/crypt.py index 042a7567b1f..259404dc95b 100755 --- a/addons/base_crypt/crypt.py +++ b/addons/base_crypt/crypt.py @@ -129,16 +129,15 @@ class users(osv.osv): # agi - 022108 # Add handlers for 'input_pw' field. - # Maps a res_users id to the salt used to encrypt its associated password. - _salt_cache = {} - _clear_uid_cache = True - def set_pw(self, cr, uid, id, name, value, args, context): if not value: raise osv.except_osv(_('Error'), _("Please specify the password !")) - self._salt_cache.setdefault(cr.dbname, {}) - salt = self._salt_cache[cr.dbname][id] = gen_salt() + 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 = encrypt_md5(value, salt) cr.execute('update res_users set password=%s where id=%s', (encrypted.encode('utf-8'), int(id))) @@ -181,8 +180,10 @@ class users(osv.osv): # Calculate an encrypted password from the user-provided # password. - self._salt_cache.setdefault(db, {}) - salt = self._salt_cache[db][id] = stored_pw[len(magic_md5):11] + 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 = encrypt_md5(password, salt) # Check if the encrypted password matches against the one in the db. @@ -197,17 +198,17 @@ class users(osv.osv): def check(self, db, uid, passwd): # Get a chance to hash all passwords in db before using the uid_cache. - if self._clear_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() - self._clear_uid_cache = False - self._salt_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() - if uid not in self._salt_cache.get(db, {}): + if uid not in obj._salt_cache: cr.execute('select login from res_users where id=%s', (int(uid),)) stored_login = cr.fetchone() if stored_login: @@ -216,7 +217,7 @@ class users(osv.osv): if not self.login(db,stored_login,passwd): return False - salt = self._salt_cache[db][uid] + salt = obj._salt_cache[uid] cr.execute('select count(id) from res_users where id=%s and password=%s', (int(uid), encrypt_md5(passwd, salt))) res = cr.fetchone()[0]