← Back to team overview

openerp-dev-web team mailing list archive

[Merge] lp:~xrg/openobject-addons/trunk-patch20 into lp:~openerp-dev/openobject-addons/trunk-dev-addons1

 

xrg has proposed merging lp:~xrg/openobject-addons/trunk-patch20 into lp:~openerp-dev/openobject-addons/trunk-dev-addons1.

Requested reviews:
  OpenERP R&D Team (openerp-dev)

For more details, see:
https://code.launchpad.net/~xrg/openobject-addons/trunk-patch20/+merge/45871
-- 
https://code.launchpad.net/~xrg/openobject-addons/trunk-patch20/+merge/45871
Your team OpenERP R&D Team is requested to review the proposed merge of lp:~xrg/openobject-addons/trunk-patch20 into lp:~openerp-dev/openobject-addons/trunk-dev-addons1.
=== added file 'base_crypt/__openerp__.py'
--- base_crypt/__openerp__.py	1970-01-01 00:00:00 +0000
+++ base_crypt/__openerp__.py	2011-01-11 15:51:39 +0000
@@ -0,0 +1,32 @@
+# -*- encoding: utf-8 -*-
+##############################################################################
+#    
+#    OpenERP, Open Source Management Solution
+#    Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU Affero General Public License as
+#    published by the Free Software Foundation, either version 3 of the
+#    License, or (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU Affero General Public License for more details.
+#
+#    You should have received a copy of the GNU Affero General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.     
+#
+##############################################################################
+{
+    "name" : "Base - Password Encryption",
+    "version" : "1.0",
+    "author" : "FS3 , Review Tiny",
+    "website" : "http://www.openerp.com";,
+    "category" : "Generic Modules/Base",
+    "description": "Module for password encryption.",
+    "depends" : ["base"],
+    "data" : [],
+    "active": False,
+    "installable": True,
+}

=== renamed file 'base_crypt/__openerp__.py' => 'base_crypt/__openerp__.py.THIS'
=== modified file 'base_crypt/crypt.py' (properties changed: +x to -x)
--- base_crypt/crypt.py	2010-12-30 06:09:52 +0000
+++ base_crypt/crypt.py	2011-01-11 15:51:39 +0000
@@ -37,14 +37,14 @@
 # USA.
 
 from random import seed, sample
-from string import letters, digits
+from string import ascii_letters, digits
 from osv import fields,osv
 import pooler
 from tools.translate import _
 
 magic_md5 = '$1$'
 
-def gen_salt( length=8, symbols=letters + digits ):
+def gen_salt( length=8, symbols=ascii_letters + digits ):
     seed()
     return ''.join( sample( symbols, length ) )
 
@@ -64,11 +64,15 @@
 # *
 # * Poul-Henning Kamp
 
-import md5
+#TODO: py>=2.6: from hashlib import md5
+import hashlib
 
 def encrypt_md5( raw_pw, salt, magic=magic_md5 ):
-    hash = md5.new( raw_pw + magic + salt )
-    stretch = md5.new( raw_pw + salt + raw_pw).digest()
+    hash = hashlib.md5()
+    hash.update( raw_pw + magic + salt )
+    st = hashlib.md5()
+    st.update( raw_pw + salt + raw_pw)
+    stretch = st.digest()
 
     for i in range( 0, len( raw_pw ) ):
         hash.update( stretch[i % 16] )
@@ -85,7 +89,7 @@
     saltedmd5 = hash.digest()
 
     for i in range( 1000 ):
-        hash = md5.new()
+        hash = hashlib.md5()
 
         if i & 1:
             hash.update( raw_pw )
@@ -162,19 +166,37 @@
     }
 
     def login(self, db, login, password):
-        cr = pooler.get_db(db).cursor()
-        cr.execute('select password, id from res_users where login=%s',
+        if not password:
+            return False
+        if db is False:
+            raise RuntimeError("Cannot authenticate to False db!")
+        cr = None
+        try:
+            cr = pooler.get_db(db).cursor()
+            return self._login(cr, db, login, password)
+        except Exception:
+            import logging
+            logging.getLogger('netsvc').exception('Could not authenticate')
+            return Exception('Access Denied')
+        finally:
+            if cr is not None:
+                cr.close()
+
+    def _login(self, cr, db, login, password):
+        cr.execute( 'SELECT password, id FROM res_users WHERE login=%s',
             (login.encode('utf-8'),))
-        stored_pw = id = cr.fetchone()
 
-        if stored_pw:
-            stored_pw = stored_pw[0]
-            id = id[1]
+        if cr.rowcount:
+            stored_pw, id = cr.fetchone()
         else:
-            # Return early if there is no such login.
+            # Return early if no one has a login name like that.
             return False
-
+    
         stored_pw = self.maybe_encrypt(cr, stored_pw, id)
+        
+        if not stored_pw:
+            # means couldn't encrypt or user is not active!
+            return False
 
         # Calculate an encrypted password from the user-provided
         # password.
@@ -183,12 +205,14 @@
             obj._salt_cache = {}
         salt = obj._salt_cache[id] = stored_pw[len(magic_md5):11]
         encrypted_pw = encrypt_md5(password, salt)
-
+    
         # Check if the encrypted password matches against the one in the db.
-        cr.execute('select id from res_users where id=%s and password=%s and active', (int(id), encrypted_pw.encode('utf-8')))
+        cr.execute('UPDATE res_users SET date=now() ' \
+                'WHERE id=%s AND password=%s AND active RETURNING id', 
+            (int(id), encrypted_pw.encode('utf-8')))
         res = cr.fetchone()
-        cr.close()
-
+        cr.commit()
+    
         if res:
             return res[0]
         else:
@@ -206,6 +230,7 @@
             return True
 
         cr = pooler.get_db(db).cursor()
+<<<<<<< TREE
         if uid not in obj._salt_cache:
             cr.execute('select login from res_users where id=%s', (int(uid),))
             stored_login = cr.fetchone()
@@ -220,8 +245,30 @@
             (int(uid), encrypt_md5(passwd, salt)))
         res = cr.fetchone()[0]
         cr.close()
+=======
+        try:
+            if uid not in self._salt_cache.get(db, {}):
+                # If we don't have cache, we have to repeat the procedure
+                # through the login function.
+                cr.execute( 'SELECT login FROM res_users WHERE id=%s', (uid,) )
+                stored_login = cr.fetchone()
+                if stored_login:
+                    stored_login = stored_login[0]
+        
+                res = self._login(cr, db, stored_login, passwd)
+                if not res:
+                    raise security.ExceptionNoTb('AccessDenied')
+            else:
+                salt = self._salt_cache[db][uid]
+                cr.execute('SELECT COUNT(*) FROM res_users WHERE id=%s AND password=%s', 
+                    (int(uid), encrypt_md5(passwd, salt)))
+                res = cr.fetchone()[0]
+        finally:
+            cr.close()
+
+>>>>>>> MERGE-SOURCE
         if not bool(res):
-            raise Exception('AccessDenied')
+            raise security.ExceptionNoTb('AccessDenied')
 
         if res:
             if self._uid_cache.has_key(db):
@@ -230,20 +277,25 @@
             else:
                 self._uid_cache[db] = {uid: passwd}
         return bool(res)
-
+    
     def maybe_encrypt(self, cr, pw, id):
-        # If the password 'pw' is not encrypted, then encrypt all passwords
-        # in the db. Returns the (possibly newly) encrypted password for 'id'.
+        """ Return the password 'pw', making sure it is encrypted.
+        
+        If the password 'pw' is not encrypted, then encrypt all active passwords
+        in the db. Returns the (possibly newly) encrypted password for 'id'.
+        """
 
-        if pw[0:len(magic_md5)] != magic_md5:
-            cr.execute('select id, password from res_users')
+        if not pw.startswith(magic_md5):
+            encrypted_res = False
+            cr.execute("SELECT id, password FROM res_users " \
+                "WHERE active=true AND password NOT LIKE '$%'")
+            # Note that we skip all passwords like $.., in anticipation for
+            # more than md5 magic prefixes.
             res = cr.fetchall()
             for i, p in res:
-                encrypted = p
-                if p[0:len(magic_md5)] != magic_md5:
-                    encrypted = encrypt_md5(p, gen_salt())
-                    cr.execute('update res_users set password=%s where id=%s',
-                        (encrypted.encode('utf-8'), int(i)))
+                encrypted = encrypt_md5(p, gen_salt())
+                cr.execute('UPDATE res_users SET password=%s where id=%s',
+                        (encrypted, i))
                 if i == id:
                     encrypted_res = encrypted
             cr.commit()

=== added file 'base_crypt/i18n/el.po'
--- base_crypt/i18n/el.po	1970-01-01 00:00:00 +0000
+++ base_crypt/i18n/el.po	2011-01-11 15:51:39 +0000
@@ -0,0 +1,27 @@
+# Translation of OpenERP Server.
+# This file contains the translation of the following modules:
+# 	* base_crypt
+#
+# Copyright (C) 2008,2009 P. Christeas <p_christ@xxxxxx>
+# <> <>, 2009.
+msgid ""
+msgstr ""
+"Project-Id-Version: OpenERP Server 5.0.0\n"
+"Report-Msgid-Bugs-To: support@xxxxxxxxxxx\n"
+"POT-Creation-Date: 2009-05-30 15:14:08+0000\n"
+"PO-Revision-Date: 2009-03-27 14:30+0200\n"
+"Last-Translator: <> <>\n"
+"Language-Team:  <>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: \n"
+"Plural-Forms: \n"
+
+#~ msgid "Module for password encryption."
+#~ msgstr "Άρθρωμα για κρυπτογράφηση κωδικών."
+
+#~ msgid "Invalid XML for View Architecture!"
+#~ msgstr "Άκυρο XML για αρχιτεκτονική προβολής!"
+
+#~ msgid "Password"
+#~ msgstr "Κωδικός"

=== modified file 'base_setup/__init__.py'
--- base_setup/__init__.py	2010-11-19 13:48:01 +0000
+++ base_setup/__init__.py	2011-01-11 15:51:39 +0000
@@ -45,9 +45,15 @@
     def get_users(self, cr, uid, context=None):
         user_obj = self.pool.get('res.users')
         user_ids = user_obj.search(cr, uid, [])
-        users = user_obj.browse(cr, uid, user_ids, context=context)
-        user_str = '\n'.join(map(lambda x: '    - %s :\n\t\tLogin : %s \n\t\tPassword : %s' % (x.name, x.login, x.password), users))
-        return _('The following users have been installed : \n')+ user_str
+        user_list = []
+        user_tmpl_nopass = _('    - %s :\n\t\tLogin : %s')
+        user_tmpl_pass =   _('    - %s :\n\t\tLogin : %s \n\t\tPassword : %s')
+        for user in user_obj.browse(cr, uid, user_ids, context=context):
+            if user.password and not user.password.startswith('$'):
+                user_list.append(user_tmpl_pass % (user.name, user.login, user.password))
+            else:
+                user_list.append(user_tmpl_nopass % (user.name, user.login))
+        return _('The following users have been installed : \n')+ '\n'.join(user_list)
 
     _columns = {
         'installed_users':fields.text('Installed Users', readonly=True),

=== modified file 'document_ftp/test_easyftp.py'
--- document_ftp/test_easyftp.py	2011-01-11 11:03:57 +0000
+++ document_ftp/test_easyftp.py	2011-01-11 15:51:39 +0000
@@ -37,7 +37,16 @@
 def get_ftp_login(cr, uid, ormobj):
     ftp = get_plain_ftp()
     user = ormobj.pool.get('res.users').read(cr, uid, uid)
+<<<<<<< TREE
     ftp.login(user.get('login',''), user.get('login',''))
+=======
+    passwd = user.get('password','')
+    if passwd.startswith("$1$"):
+        # md5 by base crypt. We cannot decode, wild guess 
+        # that passwd = login
+        passwd = user.get('login', '')
+    ftp.login(user.get('login',''), passwd)
+>>>>>>> MERGE-SOURCE
     ftp.cwd("/" + cr.dbname)
     return ftp
 

=== modified file 'document_webdav/test_davclient.py'
--- document_webdav/test_davclient.py	2010-12-07 13:39:47 +0000
+++ document_webdav/test_davclient.py	2011-01-11 15:51:39 +0000
@@ -365,6 +365,10 @@
         assert res, "uid %s not found" % uid
         self.user = res[0]['login']
         self.passwd = res[0]['password']
+        if self.passwd.startswith('$1$'):
+            # md5 by base crypt. We cannot decode, wild guess 
+            # that passwd = login
+            self.passwd = self.user
         return True
 
     def set_useragent(self, uastr):


Follow ups