Limit record access using record rules

A common need for an application is to be able to limit what records are available to each user on a specific model.

This is achieved using record rules. A record rule is a domain filter expression defined on a model that will then be added on every data query made by the affected users.

As an example, we will add a record rule on the Library books model so that the users in the employee group will only have access to books they created in the database.

Getting ready

This recipe assumes you have an instance ready, with my_module available, as described in Chapter 3, Creating Odoo Modules.

How to do it...

Record rules are added using a data XML file. To do so, perform the following steps:

  1. Ensure that the security/library_security.xml file is referenced by manifest data key:
        'data': [
            'security/library_security.xml',
            # ...
        ],
  2. We should have a security/library_security.xml data file, with a <data> section creating the security group. After it, add this second <data> section for the record rules:
      <data noupdate="1">
        <record model="ir.rule" id="library_book_user_rule">
            <field name="name">Library: see only own books</field>
            <field name="model_id" ref="model_library_book"/>
            <field name="groups" eval="[(4, ref('base.group_user'))]"/>
            <field name="domain_force">
            [('create_uid', '=', user.id)]</field>
        </record>
        <record model="ir.rule" id="library_book_all_rule">
            <field name="name">Library: see all books</field>
            <field name="model_id" ref="model_library_book"/>
            <field name="groups" eval="[(4, ref('base.group_system'))]"/>
            <field name="domain_force">[(1, '=', 1)]</field>
        </record>
      </data>

Upgrading the addon module will load the record rules into the Odoo instance.

To keep the recipe simple, we used the core employee and settings security groups. We could instead have used the Library user and manager groups as defined in the Add security access to models recipe. It's a good exercise to follow it and modify this module so that it uses those security groups instead.

How it works...

Record rules are just data records loaded into the ir.rule core model. While the file adding them could be anywhere in the module, the convention is for it to be in the security subdirectory. It is common to have a single XML file with both security groups and record rules.

Unlike groups, in the standard modules, the record rules are loaded in a data section with the noupdate="1" attribute. With this, those records will not be reloaded on a module upgrade, meaning that manual customizations on them are safe and will survive later upgrades.

To stay consistent with the official modules, we should also have our record rules inside a <data noupdate="1"> section.

Record rules can be seen from the GUI at the menu option Settings | Technical | Security | Record Rules, as shown in the following screenshot:

How it works...

Following are the most important record rule fields used in the example:

  • Name (name) is a descriptive title for the rule.
  • Object (model_id) is a reference to the model the rule applied to.
  • Groups (groups) are the security groups that the rule applies to. If none, the rule is considered global and is applied in a different way (more details follow later).
  • Rule definition (domain) is a domain expression with the record filter to apply.

The first record rule we created was for the Employee security group. It uses the domain expression [('create_uid', '=', user.id)] to select only those books where the creation user is the current user. Thus, they will only be able to see the books created by themselves.

The domain expressions used in the record rules run on the server side using ORM objects. Because of this, dot notation can be used on the fields on the left-hand side (the first tuple element). The right side (third tuple element) is a Python expression, evaluated in a context having available the user record object, for the current user, and the time Python library.

For the settings security group, we want it to be able to see all the books, independent of who created them in the database. Since it inherits the Employee group, unless we do something about it, it too will be able to see only the books created by itself.

The several (non global) record rules are joined together using the OR logical operator: each rule adds access and never removes the access. For the Library Manager to have access to all the books, we can add to it a record rule to add access to books created by other users, like this: [('create_uid', '!=', user.id)].

We chose to do differently and use the special rule [(1, '=', 1)] to unconditionally give access to all the book records. While this may seem redundant, remember that otherwise the Library user rule can be customized in a way that would keep some books out of reach to the Settings user. It is special because the first element of a domain tuple must be a field name; this exact case is the only case where that is not true.

Note

Record rules are ignored for the built-in admin user. When testing your record rules, make sure you use some other user for that.

There's more...

When a record rule is not assigned to any security group, it is marked as Global and is handled differently from the other rules.

Global record rules have a stronger effect than group level record rules, and set access restriction that those can't override. Technically, they are joined with an AND operator. In the standard modules, they are used to implement multi-company security access, so that each user can see only his company's data.

In summary, regular non global record rules are joined together with an OR operator: they are added together and a record is accessible if any of the rule grants that access. Global record rules then add restrictions to the access given by the regular record rules, using an AND operator. Restrictions added by global record rules can't be overridden by regular record rules.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.219.96.188