X-Git-Url: http://git.inspyration.org/?a=blobdiff_plain;f=openerp%2Faddons%2Fbase%2Fres%2Fres_users.py;h=5e1ea88f5ac232b1dfb21d8bd34a6dc8b16fed54;hb=5d8f738b886306489ac792cd7d50528c2e00643a;hp=31f6c7149862aa9d4c1e60d74292368ff535f892;hpb=6de2150126c17ff104325858abada6d3c2c82925;p=odoo%2Fodoo.git diff --git a/openerp/addons/base/res/res_users.py b/openerp/addons/base/res/res_users.py index 31f6c71..5e1ea88 100644 --- a/openerp/addons/base/res/res_users.py +++ b/openerp/addons/base/res/res_users.py @@ -3,7 +3,7 @@ # # OpenERP, Open Source Management Solution # Copyright (C) 2004-2009 Tiny SPRL (). -# Copyright (C) 2010-2011 OpenERP s.a. (). +# Copyright (C) 2010-2012 OpenERP s.a. (). # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -26,6 +26,7 @@ import logging from lxml import etree from lxml.builder import E import netsvc +from openerp import SUPERUSER_ID import openerp import openerp.exceptions from osv import fields,osv @@ -185,10 +186,10 @@ class res_users(osv.osv): if 'password' in o and ( 'id' not in o or o['id'] != uid ): o['password'] = '********' return o - result = super(users, self).read(cr, uid, ids, fields, context, load) + result = super(res_users, self).read(cr, uid, ids, fields, context, load) canwrite = self.pool.get('ir.model.access').check(cr, uid, 'res.users', 'write', False) if not canwrite: - if isinstance(ids, (int, float)): + if isinstance(ids, (int, long)): result = override_password(result) else: result = map(override_password, result) @@ -206,11 +207,6 @@ class res_users(osv.osv): ('login_key', 'UNIQUE (login)', 'You can not have two users with the same login !') ] - def _get_default_image(self, cr, uid, is_company, context=None): - """ Override of res.partner: multicolor avatars ! """ - image_path = openerp.modules.get_module_resource('base', 'static/src/img', 'avatar%d.png' % random.randint(0, 6)) - return tools.image_resize_image_big(open(image_path, 'rb').read().encode('base64')) - def _get_company(self,cr, uid, context=None, uid2=False): if not uid2: uid2 = uid @@ -238,9 +234,9 @@ class res_users(osv.osv): dataobj = self.pool.get('ir.model.data') result = [] try: - dummy,group_id = dataobj.get_object_reference(cr, 1, 'base', 'group_user') + dummy,group_id = dataobj.get_object_reference(cr, SUPERUSER_ID, 'base', 'group_user') result.append(group_id) - dummy,group_id = dataobj.get_object_reference(cr, 1, 'base', 'group_partner_manager') + dummy,group_id = dataobj.get_object_reference(cr, SUPERUSER_ID, 'base', 'group_partner_manager') result.append(group_id) except ValueError: # If these groups does not exists anymore @@ -248,13 +244,14 @@ class res_users(osv.osv): return result _defaults = { - 'password' : '', - 'active' : True, + 'password': '', + 'active': True, 'customer': False, 'menu_id': _get_menu, 'company_id': _get_company, 'company_ids': _get_companies, 'groups_id': _get_group, + 'image': lambda self, cr, uid, ctx={}: self.pool.get('res.partner')._get_default_image(cr, uid, False, ctx, colorize=True), } def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False): @@ -265,7 +262,7 @@ class res_users(osv.osv): """ if not view_id and view_type == 'form': return self.pool.get('res.partner').fields_view_get(cr, uid, view_id, view_type, context, toolbar, submenu) - return super(users, self).fields_view_get(cr, uid, view_id, view_type, context, toolbar, submenu) + return super(res_users, self).fields_view_get(cr, uid, view_id, view_type, context, toolbar, submenu) # User can write to a few of her own fields (but not her groups for example) SELF_WRITEABLE_FIELDS = ['password', 'signature', 'action_id', 'company_id', 'email', 'name', 'image', 'image_medium', 'image_small'] @@ -279,11 +276,11 @@ class res_users(osv.osv): break else: if 'company_id' in values: - if not (values['company_id'] in self.read(cr, 1, uid, ['company_ids'], context=context)['company_ids']): + if not (values['company_id'] in self.read(cr, SUPERUSER_ID, uid, ['company_ids'], context=context)['company_ids']): del values['company_id'] uid = 1 # safe fields only, so we write as super-user to bypass access rights - res = super(users, self).write(cr, uid, ids, values, context=context) + res = super(res_users, self).write(cr, uid, ids, values, context=context) # clear caches linked to the users self.pool.get('ir.model.access').call_cache_clearing_methods(cr) @@ -305,7 +302,7 @@ class res_users(osv.osv): for id in ids: if id in self._uid_cache[db]: del self._uid_cache[db][id] - return super(users, self).unlink(cr, uid, ids, context=context) + return super(res_users, self).unlink(cr, uid, ids, context=context) def name_search(self, cr, user, name='', args=None, operator='ilike', context=None, limit=100): if not args: @@ -328,10 +325,10 @@ class res_users(osv.osv): name=(copy_pattern % user2copy['name']), ) copydef.update(default) - return super(users, self).copy(cr, uid, id, copydef, context) + return super(res_users, self).copy(cr, uid, id, copydef, context) def context_get(self, cr, uid, context=None): - user = self.browse(cr, uid, uid, context) + user = self.browse(cr, SUPERUSER_ID, uid, context) result = {} for k in self._all_columns.keys(): if k.startswith('context_'): @@ -349,9 +346,60 @@ class res_users(osv.osv): def action_get(self, cr, uid, context=None): dataobj = self.pool.get('ir.model.data') - data_id = dataobj._get_id(cr, 1, 'base', 'action_res_users_my') + data_id = dataobj._get_id(cr, SUPERUSER_ID, 'base', 'action_res_users_my') return dataobj.browse(cr, uid, data_id, context=context).res_id + def check_super(self, passwd): + if passwd == tools.config['admin_passwd']: + return True + else: + raise openerp.exceptions.AccessDenied() + + def check_credentials(self, cr, uid, password): + """ Override this method to plug additional authentication methods""" + res = self.search(cr, SUPERUSER_ID, [('id','=',uid),('password','=',password)]) + if not res: + raise openerp.exceptions.AccessDenied() + + def login(self, db, login, password): + if not password: + return False + user_id = False + cr = pooler.get_db(db).cursor() + try: + # autocommit: our single update request will be performed atomically. + # (In this way, there is no opportunity to have two transactions + # interleaving their cr.execute()..cr.commit() calls and have one + # of them rolled back due to a concurrent access.) + cr.autocommit(True) + # check if user exists + res = self.search(cr, SUPERUSER_ID, [('login','=',login)]) + if res: + user_id = res[0] + # check credentials + self.check_credentials(cr, user_id, password) + # We effectively unconditionally write the res_users line. + # Even w/ autocommit there's a chance the user row will be locked, + # in which case we can't delay the login just for the purpose of + # update the last login date - hence we use FOR UPDATE NOWAIT to + # try to get the lock - fail-fast + # Failing to acquire the lock on the res_users row probably means + # another request is holding it. No big deal, we don't want to + # prevent/delay login in that case. It will also have been logged + # as a SQL error, if anyone cares. + try: + cr.execute("SELECT id FROM res_users WHERE id=%s FOR UPDATE NOWAIT", str(user_id)) + cr.execute("UPDATE res_users SET login_date = now() AT TIME ZONE 'UTC' WHERE id=%s", str(user_id)) + except Exception, e: + _logger.exception("Failed to update last_login for db:%s login:%s", db, login) + except openerp.exceptions.AccessDenied: + _logger.info("Login failed for db:%s login:%s", db, login) + user_id = False + finally: + cr.close() + + return user_id + def authenticate(self, db, login, password, user_agent_env): """Verifies and returns the user ID corresponding to the given ``login`` and ``password`` combination, or False if there was @@ -370,8 +418,8 @@ class res_users(osv.osv): if user_agent_env and user_agent_env.get('base_location'): cr = pooler.get_db(db).cursor() try: - self.pool.get('ir.config_parameter').set_param(cr, uid, 'web.base.url', - user_agent_env['base_location']) + base = user_agent_env['base_location'] + self.pool.get('ir.config_parameter').set_param(cr, uid, 'web.base.url', base) cr.commit() except Exception: _logger.exception("Failed to update web.base.url configuration parameter") @@ -379,54 +427,8 @@ class res_users(osv.osv): cr.close() return uid - def login(self, db, login, password): - if not password: - return False - cr = pooler.get_db(db).cursor() - try: - # autocommit: our single request will be performed atomically. - # (In this way, there is no opportunity to have two transactions - # interleaving their cr.execute()..cr.commit() calls and have one - # of them rolled back due to a concurrent access.) - # We effectively unconditionally write the res_users line. - cr.autocommit(True) - # Even w/ autocommit there's a chance the user row will be locked, - # in which case we can't delay the login just for the purpose of - # update the last login date - hence we use FOR UPDATE NOWAIT to - # try to get the lock - fail-fast - cr.execute("""SELECT id from res_users - WHERE login=%s AND password=%s - AND active FOR UPDATE NOWAIT""", - (tools.ustr(login), tools.ustr(password))) - cr.execute("""UPDATE res_users - SET login_date = now() AT TIME ZONE 'UTC' - WHERE login=%s AND password=%s AND active - RETURNING id""", - (tools.ustr(login), tools.ustr(password))) - except Exception: - # Failing to acquire the lock on the res_users row probably means - # another request is holding it. No big deal, we don't want to - # prevent/delay login in that case. It will also have been logged - # as a SQL error, if anyone cares. - cr.execute("""SELECT id from res_users - WHERE login=%s AND password=%s - AND active""", - (tools.ustr(login), tools.ustr(password))) - finally: - res = cr.fetchone() - cr.close() - if res: - return res[0] - return False - - def check_super(self, passwd): - if passwd == tools.config['admin_passwd']: - return True - else: - raise openerp.exceptions.AccessDenied() - def check(self, db, uid, passwd): - """Verifies that the given (uid, password) pair is authorized for the database ``db`` and + """Verifies that the given (uid, password) is authorized for the database ``db`` and raise an exception if it is not.""" if not passwd: # empty passwords disallowed for obvious security reasons @@ -435,32 +437,14 @@ class res_users(osv.osv): return cr = pooler.get_db(db).cursor() try: - cr.execute('SELECT COUNT(1) FROM res_users WHERE id=%s AND password=%s AND active=%s', - (int(uid), passwd, True)) - res = cr.fetchone()[0] - if not res: - raise openerp.exceptions.AccessDenied() + self.check_credentials(cr, uid, passwd) if self._uid_cache.has_key(db): - ulist = self._uid_cache[db] - ulist[uid] = passwd + self._uid_cache[db][uid] = passwd else: self._uid_cache[db] = {uid:passwd} finally: cr.close() - def access(self, db, uid, passwd, sec_level, ids): - if not passwd: - return False - cr = pooler.get_db(db).cursor() - try: - cr.execute('SELECT id FROM res_users WHERE id=%s AND password=%s', (uid, passwd)) - res = cr.fetchone() - if not res: - raise openerp.exceptions.AccessDenied() - return res[0] - finally: - cr.close() - def change_password(self, cr, uid, old_passwd, new_passwd, context=None): """Change current user password. Old password must be provided explicitly to prevent hijacking an existing user session, or for cases where the cleartext @@ -554,7 +538,7 @@ class groups_implied(osv.osv): return memo[g] res = {} - for g in self.browse(cr, 1, ids, context): + for g in self.browse(cr, SUPERUSER_ID, ids, context): res[g.id] = map(int, computed_set(g)) return res @@ -583,8 +567,6 @@ class groups_implied(osv.osv): super(groups_implied, self).write(cr, uid, gids, vals, context) return res -groups_implied() - class users_implied(osv.osv): _inherit = 'res.users' @@ -608,10 +590,6 @@ class users_implied(osv.osv): super(users_implied, self).write(cr, uid, [user.id], vals, context) return res -users_implied() - - - # # Extension of res.groups and res.users for the special groups view in the users # form. This extension presents groups with selection and boolean widgets: @@ -705,7 +683,7 @@ class groups_view(osv.osv): def get_user_groups_view(self, cr, uid, context=None): try: - view = self.pool.get('ir.model.data').get_object(cr, 1, 'base', 'user_groups_view', context) + view = self.pool.get('ir.model.data').get_object(cr, SUPERUSER_ID, 'base', 'user_groups_view', context) assert view and view._table_name == 'ir.ui.view' except Exception: view = False @@ -754,8 +732,6 @@ class groups_view(osv.osv): res.append((False, 'boolean', others)) return res -groups_view() - class users_view(osv.osv): _inherit = 'res.users' @@ -847,6 +823,4 @@ class users_view(osv.osv): } return res -users_view() - # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: