[IMP] base: use ir.model.access on transient models
Before this commit models with the `_transient` flag were ignored in ir.model.access verifications. Only an implicit ir.rule with the domain (create_uid=user.id) was applied to avoid most side effects. The problem is that, often, the security does not lie in side-effects of abusing of somebody else's wizard record but in the fact that the wizard methods blindly trust only the right users are creating these records. Too often, too many sudo were used and creating wizard with chosen values could lead to an abuse scenario. Instead, explicitly require the developer to declare security rules the same way as on any other model.
This commit is contained in:
@@ -1455,7 +1455,7 @@ class IrModelAccess(models.Model):
|
||||
|
||||
name = fields.Char(required=True, index=True)
|
||||
active = fields.Boolean(default=True, help='If you uncheck the active field, it will disable the ACL without deleting it (if you delete a native ACL, it will be re-created when you reload the module).')
|
||||
model_id = fields.Many2one('ir.model', string='Object', required=True, domain=[('transient', '=', False)], index=True, ondelete='cascade')
|
||||
model_id = fields.Many2one('ir.model', string='Object', required=True, index=True, ondelete='cascade')
|
||||
group_id = fields.Many2one('res.groups', string='Group', ondelete='cascade', index=True)
|
||||
perm_read = fields.Boolean(string='Read Access')
|
||||
perm_write = fields.Boolean(string='Write Access')
|
||||
@@ -1533,8 +1533,6 @@ class IrModelAccess(models.Model):
|
||||
# TransientModel records have no access rights, only an implicit access rule
|
||||
if model not in self.env:
|
||||
_logger.error('Missing model %s', model)
|
||||
elif self.env[model].is_transient():
|
||||
return True
|
||||
|
||||
# We check if a specific rule exists
|
||||
self._cr.execute("""SELECT MAX(CASE WHEN perm_{mode} THEN 1 ELSE 0 END)
|
||||
|
||||
@@ -62,11 +62,6 @@ class IrRule(models.Model):
|
||||
for rule in self:
|
||||
rule['global'] = not rule.groups
|
||||
|
||||
@api.constrains('model_id')
|
||||
def _check_model_transience(self):
|
||||
if any(self.env[rule.model_id.model].is_transient() for rule in self):
|
||||
raise ValidationError(_('Rules can not be applied on Transient models.'))
|
||||
|
||||
@api.constrains('model_id')
|
||||
def _check_model_name(self):
|
||||
# Don't allow rules on rules records (this model).
|
||||
|
||||
+1
-13
@@ -557,7 +557,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
|
||||
if ModelClass._transient:
|
||||
assert ModelClass._log_access, \
|
||||
"TransientModels must have log_access turned on, " \
|
||||
"in order to implement their access rights policy"
|
||||
"in order to implement their vacuum policy"
|
||||
|
||||
# link the class to the registry, and update the registry
|
||||
ModelClass.pool = pool
|
||||
@@ -3241,9 +3241,6 @@ Record ids: %(records)s
|
||||
forbidden = invalid.exists()
|
||||
if forbidden:
|
||||
# the invalid records are (partially) hidden by access rules
|
||||
if self.is_transient():
|
||||
raise AccessError(_('For this kind of document, you may only access records you created yourself.\n\n(Document type: %s)') % (self._description,))
|
||||
|
||||
raise self.env['ir.rule']._make_access_error(operation, forbidden)
|
||||
|
||||
# If we get here, the invalid records are not in the database.
|
||||
@@ -4166,15 +4163,6 @@ Record ids: %(records)s
|
||||
if table not in query.tables:
|
||||
query.tables.append(table)
|
||||
|
||||
if self._transient:
|
||||
# One single implicit access rule for transient models: owner only!
|
||||
# This is ok because we assert that TransientModels always have
|
||||
# log_access enabled, so that 'create_uid' is always there.
|
||||
domain = [('create_uid', '=', self._uid)]
|
||||
tquery = self._where_calc(domain, active_test=False)
|
||||
apply_rule(tquery.where_clause, tquery.where_clause_params, tquery.tables)
|
||||
return
|
||||
|
||||
# apply main rules on the object
|
||||
Rule = self.env['ir.rule']
|
||||
where_clause, where_params, tables = Rule.domain_get(self._name, mode)
|
||||
|
||||
@@ -443,17 +443,10 @@ def load_modules(db, force_demo=False, status=None, update_module=False):
|
||||
env = api.Environment(cr, SUPERUSER_ID, {})
|
||||
cr.execute("""select model,name from ir_model where id NOT IN (select distinct model_id from ir_model_access)""")
|
||||
for (model, name) in cr.fetchall():
|
||||
if model in registry and not registry[model]._abstract and not registry[model]._transient:
|
||||
if model in registry and not registry[model]._abstract:
|
||||
_logger.warning('The model %s has no access rules, consider adding one. E.g. access_%s,access_%s,model_%s,base.group_user,1,0,0,0',
|
||||
model, model.replace('.', '_'), model.replace('.', '_'), model.replace('.', '_'))
|
||||
|
||||
# Temporary warning while we remove access rights on osv_memory objects, as they have
|
||||
# been replaced by owner-only access rights
|
||||
cr.execute("""select distinct mod.model, mod.name from ir_model_access acc, ir_model mod where acc.model_id = mod.id""")
|
||||
for (model, name) in cr.fetchall():
|
||||
if model in registry and registry[model]._transient:
|
||||
_logger.warning('The transient model %s (%s) should not have explicit access rules!', model, name)
|
||||
|
||||
cr.execute("SELECT model from ir_model")
|
||||
for (model,) in cr.fetchall():
|
||||
if model in registry:
|
||||
|
||||
Reference in New Issue
Block a user