Merge lp:~camptocamp/openobject-addons/improve_auth_crypt_3_please_launchpad_work-nbi into lp:openobject-addons/7.0

Proposed by Nicolas Bessi - Camptocamp
Status: Merged
Merge reported by: Olivier Dony (Odoo)
Merged at revision: not available
Proposed branch: lp:~camptocamp/openobject-addons/improve_auth_crypt_3_please_launchpad_work-nbi
Merge into: lp:openobject-addons/7.0
Diff against target: 67 lines (+30/-6)
1 file modified
auth_crypt/auth_crypt.py (+30/-6)
To merge this branch: bzr merge lp:~camptocamp/openobject-addons/improve_auth_crypt_3_please_launchpad_work-nbi
Reviewer Review Type Date Requested Status
Olivier Dony (Odoo) Needs Fixing
Review via email: mp+206476@code.launchpad.net

Commit message

[IMP] Add an init function on res.users to encrypt all passwords when installing module and avoid plain passwords for deactivated users.

Description of the change

([IMP] module auth_crypt use sha256 by default to encrypt password. The modification keeps retro compatibility.) REMOVED as disscussed with Olivier

[IMP] Add an init function on res.users to encrypt all passwords when installing module and avoid plain password for deactivated users.

To post a comment you must log in.
Revision history for this message
Olivier Dony (Odoo) (odo-openerp) wrote :

Hi,

As discussed in bug 1280152 comments, we should consider these as 2 separate issues, so this MP could start by dealing with the first one (the lazy password encryption issue).

For this part, your init() method looks fine, but there are already multiple instances of the salting+hashing dance. As you're adding one more, it seems a good opportunity to refactor a bit and extract that pattern into a private method, something like:

def _set_user_password(self, cr, uid, user_id, password, context=None):
     password_hash = md5_crypt(password, gen_salt()) # TODO: update default algo in trunk
     cr.execute("UPDATE res_users SET password='', password_crypt=%s WHERE id=%s",
                (password_hash, user_id))

Thanks!

review: Needs Fixing
Revision history for this message
Nicolas Bessi - Camptocamp (nbessi-c2c-deactivatedaccount) wrote :

Hello,

I have made the modification as required only the init function is in the MP

Revision history for this message
Nicolas Bessi - Camptocamp (nbessi-c2c-deactivatedaccount) wrote :

Hello Olivier,

Any news on this one

Regards

Nicolas

Revision history for this message
Olivier Dony (Odoo) (odo-openerp) wrote :

Thanks for the update! Moved to github for merge (added guard for NULL passwords): https://github.com/odoo/odoo/pull/628

Revision history for this message
Olivier Dony (Odoo) (odo-openerp) wrote :

Merged in 7.0 at https://github.com/odoo-dev/odoo/commit/f29ff5ef, so closing it.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'auth_crypt/auth_crypt.py'
--- auth_crypt/auth_crypt.py 2013-08-01 16:27:04 +0000
+++ auth_crypt/auth_crypt.py 2014-03-19 14:52:30 +0000
@@ -105,6 +105,7 @@
105105
106 return magic + salt + '$' + rearranged106 return magic + salt + '$' + rearranged
107107
108
108def sh256crypt(cls, password, salt, magic=magic_sha256):109def sh256crypt(cls, password, salt, magic=magic_sha256):
109 iterations = 1000110 iterations = 1000
110 # see http://en.wikipedia.org/wiki/PBKDF2111 # see http://en.wikipedia.org/wiki/PBKDF2
@@ -114,16 +115,41 @@
114 result = result.encode('base64') # doesnt seem to be crypt(3) compatible115 result = result.encode('base64') # doesnt seem to be crypt(3) compatible
115 return '%s%s$%s' % (magic_sha256, salt, result)116 return '%s%s$%s' % (magic_sha256, salt, result)
116117
118
117class res_users(osv.osv):119class res_users(osv.osv):
118 _inherit = "res.users"120 _inherit = "res.users"
119121
122 def init(self, cr):
123 """Encrypt all passwords at module installation"""
124 cr.execute("SELECT id, password FROM res_users WHERE password != ''",)
125 to_encrypt = cr.fetchall()
126 if to_encrypt:
127 for user in to_encrypt:
128 self._set_encrypted_password(cr, user[0], user[1])
129 return True
130
131 def _set_encrypted_password(self, cr, user_id, plain_password):
132 """Set an encrypted password for a given user
133
134 :param cr: database cursor
135 :param user_id: user_id
136 :param plain_password: plain password to encrypt
137
138 :returns: user id
139
140 """
141 salt = gen_salt()
142 stored_password_crypt = md5crypt(plain_password, salt)
143 cr.execute("UPDATE res_users SET password='', password_crypt=%s WHERE id=%s",
144 (stored_password_crypt, user_id))
145 return user_id
146
120 def set_pw(self, cr, uid, id, name, value, args, context):147 def set_pw(self, cr, uid, id, name, value, args, context):
121 if value:148 if value:
122 encrypted = md5crypt(value, gen_salt())149 self._set_encrypted_password(cr, id, value)
123 cr.execute("update res_users set password='', password_crypt=%s where id=%s", (encrypted, id))
124 del value150 del value
125151
126 def get_pw( self, cr, uid, ids, name, args, context ):152 def get_pw(self, cr, uid, ids, name, args, context):
127 cr.execute('select id, password from res_users where id in %s', (tuple(map(int, ids)),))153 cr.execute('select id, password from res_users where id in %s', (tuple(map(int, ids)),))
128 stored_pws = cr.fetchall()154 stored_pws = cr.fetchall()
129 res = {}155 res = {}
@@ -144,9 +170,7 @@
144 if cr.rowcount:170 if cr.rowcount:
145 stored_password, stored_password_crypt = cr.fetchone()171 stored_password, stored_password_crypt = cr.fetchone()
146 if stored_password and not stored_password_crypt:172 if stored_password and not stored_password_crypt:
147 salt = gen_salt()173 self._set_encrypted_password(cr, uid, stored_password)
148 stored_password_crypt = md5crypt(stored_password, salt)
149 cr.execute("UPDATE res_users SET password='', password_crypt=%s WHERE id=%s", (stored_password_crypt, uid))
150 try:174 try:
151 return super(res_users, self).check_credentials(cr, uid, password)175 return super(res_users, self).check_credentials(cr, uid, password)
152 except openerp.exceptions.AccessDenied:176 except openerp.exceptions.AccessDenied: