-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Draft: [16.0][MIG] #10965 auditlog_security #3029
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: 16.0
Are you sure you want to change the base?
Changes from all commits
f99f33a
15c16c0
381a2d1
8bd9447
e01d5b4
339a9d5
6af2d6c
f5ea50d
9f29a3f
dee7eb3
bc76353
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
========================== | ||
Audit Log User Permissions | ||
========================== | ||
|
||
.. | ||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | ||
!! This file is generated by oca-gen-addon-readme !! | ||
!! changes will be overwritten. !! | ||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | ||
!! source digest: sha256:f98c0209d43e543c4900a35144d6189d6a65aa2a3e462333582408b79f57c733 | ||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | ||
|
||
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png | ||
:target: https://odoo-community.org/page/development-status | ||
:alt: Beta | ||
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png | ||
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html | ||
:alt: License: AGPL-3 | ||
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fserver--tools-lightgray.png?logo=github | ||
:target: https://github.com/OCA/server-tools/tree/16.0/auditlog_security | ||
:alt: OCA/server-tools | ||
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png | ||
:target: https://translation.odoo-community.org/projects/server-tools-16-0/server-tools-16-0-auditlog_security | ||
:alt: Translate me on Weblate | ||
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png | ||
:target: https://runboat.odoo-community.org/builds?repo=OCA/server-tools&target_branch=16.0 | ||
:alt: Try me on Runboat | ||
|
||
|badge1| |badge2| |badge3| |badge4| |badge5| | ||
|
||
This module allows extends auditlog, allowing specific log lines to be viewed only | ||
by users belonging to specific views, while all other lines are allowed only to | ||
administrator. | ||
|
||
**Table of contents** | ||
|
||
.. contents:: | ||
:local: | ||
|
||
Usage | ||
===== | ||
|
||
Go to `Settings / Technical / Audit / Rules` to subscribe rules. A rule defines | ||
which operations to log for a given data model. | ||
The rule is now extended with a new field permission_ids, that tells us wich groups will | ||
be allowed to read the lines produced by this rule. | ||
If permission_ids is left empty, the default will be: | ||
"auditlog lines visible only by user in Settings group, which is the default | ||
for the auditlog module" | ||
|
||
|
||
Then, check logs in the `Settings / Technical / Audit / Logs` menu. You can | ||
group them by user sessions, date, data model , HTTP requests. | ||
|
||
Known issues / Roadmap | ||
====================== | ||
|
||
|
||
|
||
Bug Tracker | ||
=========== | ||
|
||
Bugs are tracked on `GitHub Issues <https://github.com/OCA/server-tools/issues>`_. | ||
In case of trouble, please check there if your issue has already been reported. | ||
If you spotted it first, help us to smash it by providing a detailed and welcomed | ||
`feedback <https://github.com/OCA/server-tools/issues/new?body=module:%20auditlog_security%0Aversion:%2016.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_. | ||
|
||
Do not contact contributors directly about support or help with technical issues. | ||
|
||
Credits | ||
======= | ||
|
||
Authors | ||
~~~~~~~ | ||
|
||
* Therp B.V. | ||
|
||
Contributors | ||
~~~~~~~~~~~~ | ||
|
||
* Giovanni Francesco Capalbo <giovanni@therp.nl> | ||
|
||
Maintainers | ||
~~~~~~~~~~~ | ||
|
||
This module is maintained by the OCA. | ||
|
||
.. image:: https://odoo-community.org/logo.png | ||
:alt: Odoo Community Association | ||
:target: https://odoo-community.org | ||
|
||
OCA, or the Odoo Community Association, is a nonprofit organization whose | ||
mission is to support the collaborative development of Odoo features and | ||
promote its widespread use. | ||
|
||
This module is part of the `OCA/server-tools <https://github.com/OCA/server-tools/tree/16.0/auditlog_security>`_ project on GitHub. | ||
|
||
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). | ||
|
||
from . import models |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
# Copyright 2021 Therp B.V. <https://www.therp.nl> | ||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). | ||
|
||
{ | ||
"name": "Audit Log User Permissions", | ||
"version": "16.0.1.0.0", | ||
"author": "Therp B.V.,Odoo Community Association (OCA)", | ||
"license": "AGPL-3", | ||
"website": "https://github.com/OCA/server-tools", | ||
"category": "Tools", | ||
"summary": """Allow regular users to view Audit log lines | ||
via the form view of the relevant model""", | ||
"depends": [ | ||
"auditlog", | ||
"contacts", | ||
], | ||
"data": [ | ||
"security/res_groups.xml", | ||
"views/auditlog_view.xml", | ||
"security/ir.model.access.csv", | ||
"security/ir_rule.xml", | ||
], | ||
"application": True, | ||
"installable": True, | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
# Copyright 2021-2025 Therp B.V. | ||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). | ||
|
||
from . import auditlog_rule | ||
from . import auditlog_line_access_rule | ||
from . import auditlog_log_line |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
# Copyright 2021-2024 Therp B.V. | ||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). | ||
|
||
from odoo import fields, models | ||
|
||
|
||
class AuditlogLineAccessRule(models.Model): | ||
_name = "auditlog.line.access.rule" | ||
_description = "Auditlog Line Access Rule" | ||
|
||
name = fields.Char() | ||
|
||
field_ids = fields.Many2many("ir.model.fields") | ||
group_ids = fields.Many2many( | ||
"res.groups", | ||
help="""Groups that will be allowed to see the logged fields, if left empty | ||
default will be all users with a login""", | ||
) | ||
model_id = fields.Many2one( | ||
"ir.model", related="auditlog_rule_id.model_id", readonly=True | ||
) | ||
auditlog_rule_id = fields.Many2one( | ||
"auditlog.rule", "auditlog_access_rule_ids", readonly=True, > | ||
) | ||
state = fields.Selection(related="auditlog_rule_id.state", readonly=True) |
Original file line number | Diff line number | Diff line change | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,40 @@ | ||||||||||||||||
# Copyright 2022-2024 Therp B.V. | ||||||||||||||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). | ||||||||||||||||
|
||||||||||||||||
from odoo import api, fields, models | ||||||||||||||||
from odoo.osv.expression import OR | ||||||||||||||||
|
||||||||||||||||
|
||||||||||||||||
class AuditlogLogLine(models.Model): | ||||||||||||||||
_inherit = "auditlog.log.line" | ||||||||||||||||
_order = "create_date desc" | ||||||||||||||||
|
||||||||||||||||
user_id = fields.Many2one(related="log_id.user_id") | ||||||||||||||||
method = fields.Char(related="log_id.method") | ||||||||||||||||
model_id = fields.Many2one(related="log_id.model_id", store=True, reaonly=True) | ||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @ntsirintanis Typo There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
I still strongly think those fields shouldn't be stored, and related fields are readonly by default |
||||||||||||||||
res_id = fields.Integer(related="log_id.res_id") | ||||||||||||||||
rule_id = fields.Many2one("auditlog.rule", compute="_compute_rule_id", store=True) | ||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
see below |
||||||||||||||||
allowed_group_ids = fields.Many2many( | ||||||||||||||||
"res.groups", | ||||||||||||||||
compute=lambda self: self.update({"allowed_group_ids": False}), | ||||||||||||||||
search="_search_allowed_group_ids", | ||||||||||||||||
) | ||||||||||||||||
|
||||||||||||||||
def _search_allowed_group_ids(self, operator, value): | ||||||||||||||||
hbrunn marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||
access_rules = self.env["auditlog.line.access.rule"].search( | ||||||||||||||||
["|", ("group_ids", operator, value), ("group_ids", "=", False)] | ||||||||||||||||
) | ||||||||||||||||
domains = [] | ||||||||||||||||
for access_rule in access_rules: | ||||||||||||||||
domain = [("rule_id", "=", access_rule.auditlog_rule_id.id)] | ||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||
if access_rule.field_ids: | ||||||||||||||||
domain.append(("field_id", "in", access_rule.field_ids.ids)) | ||||||||||||||||
domains.append(domain) | ||||||||||||||||
return OR(domains) | ||||||||||||||||
|
||||||||||||||||
@api.depends("model_id") | ||||||||||||||||
def _compute_rule_id(self): | ||||||||||||||||
for line in self: | ||||||||||||||||
line.rule_id = self.env["auditlog.rule"].search( | ||||||||||||||||
[("model_id", "=", line.model_id.id)] | ||||||||||||||||
) | ||||||||||||||||
Comment on lines
+34
to
+40
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
# Copyright 2021-2024 Therp B.V. | ||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). | ||
|
||
from odoo import _, api, fields, models, modules, tools | ||
|
||
|
||
class AuditlogRule(models.Model): | ||
_inherit = "auditlog.rule" | ||
|
||
auditlog_line_access_rule_ids = fields.One2many( | ||
"auditlog.line.access.rule", "auditlog_rule_id" | ||
) | ||
server_action_id = fields.Many2one( | ||
"ir.actions.server", | ||
"Server Action", | ||
) | ||
log_selected_fields_only = fields.Boolean( | ||
help="Log only the selected fields, to save space avoid large DB data.", | ||
) | ||
|
||
@api.model | ||
@tools.ormcache("model_name") | ||
def _get_field_names_of_rule(self, model_name): | ||
"""Memory-cached list of fields per rule""" | ||
rule = ( | ||
self.env["auditlog.rule"] | ||
.sudo() | ||
.search([("model_id.model", "=", model_name)], limit=1) | ||
) | ||
if rule.auditlog_line_access_rule_ids: | ||
return rule.mapped("auditlog_line_access_rule_ids.field_ids.name") | ||
return [] | ||
|
||
@api.model | ||
@tools.ormcache("model_name") | ||
def _get_log_selected_fields_only(self, model_name): | ||
"""Memory-cached translation of model to rule""" | ||
hbrunn marked this conversation as resolved.
Show resolved
Hide resolved
|
||
rule = ( | ||
self.env["auditlog.rule"] | ||
.sudo() | ||
.search([("model_id.model", "=", model_name)], limit=1) | ||
) | ||
return rule.log_selected_fields_only | ||
|
||
@api.model | ||
def get_auditlog_fields(self, model): | ||
res = super(AuditlogRule, self).get_auditlog_fields(model) | ||
if self._get_log_selected_fields_only(model._name): | ||
selected_field_names = self._get_field_names_of_rule(model._name) | ||
# we re-use the checks on non-stored fields from super. | ||
res = [x for x in selected_field_names if x in res] | ||
return res | ||
|
||
def write(self, values): | ||
cache_invalidating_fields = [ | ||
"state", | ||
"auditlog_line_access_rule_ids", | ||
"log_selected_fields_only", | ||
] | ||
if any([field in values.keys() for field in cache_invalidating_fields]): | ||
# clear cache for all ormcache methods. | ||
self.clear_caches() | ||
res = super().write(values) | ||
if self._register_hook(): | ||
modules.registry.Registry(self.env.cr.dbname).signal_changes() | ||
Comment on lines
+64
to
+65
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. super does this already. my suggestion is to replace line 62 with modules.registry.Registry(self.env.cr.dbname).signal_changes() |
||
return res | ||
|
||
@api.onchange("model_id") | ||
def onchange_model_id(self): | ||
# if model changes we must wipe out all field ids | ||
self.auditlog_line_access_rule_ids = False | ||
|
||
@api.model | ||
def _get_view_log_lines_action(self): | ||
assert self.env.context.get("active_model") | ||
assert self.env.context.get("active_ids") | ||
model = ( | ||
self.env["ir.model"] | ||
.sudo() | ||
.search([("model", "=", self.env.context.get("active_model"))]) | ||
) | ||
domain = [ | ||
("model_id", "=", model.id), | ||
("res_id", "in", self.env.context.get("active_ids")), | ||
] | ||
return { | ||
"name": _("View Log Lines"), | ||
"res_model": "auditlog.log.line", | ||
"view_mode": "tree,form", | ||
"view_id": False, | ||
"domain": domain, | ||
"type": "ir.actions.act_window", | ||
} | ||
|
||
def _create_server_action(self): | ||
self.ensure_one() | ||
code = "action = env['auditlog.rule']._get_view_log_lines_action()" | ||
server_action = ( | ||
self.env["ir.actions.server"] | ||
.sudo() | ||
.create( | ||
{ | ||
"name": "View Log Lines", | ||
"model_id": self.model_id.id, | ||
"state": "code", | ||
"code": code, | ||
hbrunn marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
) | ||
) | ||
self.write({"server_action_id": server_action.id}) | ||
return server_action | ||
|
||
def subscribe(self): | ||
for rule in self: | ||
server_action = rule._create_server_action() | ||
hbrunn marked this conversation as resolved.
Show resolved
Hide resolved
|
||
server_action.create_action() | ||
res = super().subscribe() | ||
if res: | ||
self.action_id.write( | ||
{"groups_id": [(6, 0, [self.env.ref("base.group_system").id])]} | ||
) | ||
return res | ||
|
||
def unsubscribe(self): | ||
for rule in self: | ||
rule.server_action_id.unlink() | ||
return super().unsubscribe() |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
* Giovanni Francesco Capalbo <giovanni@therp.nl> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
This module allows extends auditlog, allowing specific log lines to be viewed only | ||
by users belonging to specific views, while all other lines are allowed only to | ||
administrator. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
Go to `Settings / Technical / Audit / Rules` to subscribe rules. A rule defines | ||
which operations to log for a given data model. | ||
The rule is now extended with a new field permission_ids, that tells us wich groups will | ||
be allowed to read the lines produced by this rule. | ||
If permission_ids is left empty, the default will be: | ||
"auditlog lines visible only by user in Settings group, which is the default | ||
for the auditlog module" | ||
|
||
|
||
Then, check logs in the `Settings / Technical / Audit / Logs` menu. You can | ||
group them by user sessions, date, data model , HTTP requests. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink | ||
access_auditlog_log_line_user,auditlog_log_line_user,auditlog.model_auditlog_log_line,base.group_user,1,0,0,0 | ||
access_auditlog_line_access_rule_admin,auditlog_line_access_rule_admin,model_auditlog_line_access_rule,base.group_erp_manager,1,1,1,1 | ||
hbrunn marked this conversation as resolved.
Show resolved
Hide resolved
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
<?xml version="1.0" encoding="utf-8" ?> | ||
<odoo noupdate="0"> | ||
|
||
<record id="auditlog_log_line_rule_base_user" model="ir.rule"> | ||
<field name="name">Access to auditlog.log.line</field> | ||
<field name="model_id" ref="auditlog.model_auditlog_log_line" /> | ||
<field name="groups" eval="[(4, ref('base.group_user'))]" /> | ||
<field name="domain_force">[('allowed_group_ids', 'in', user.groups_id.ids)] | ||
</field> | ||
</record> | ||
hbrunn marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
<record id="auditlog_log_line_rule_auditlog_admin" model="ir.rule"> | ||
<field name="name">Access to auditlog.log.line admin</field> | ||
<field name="model_id" ref="auditlog.model_auditlog_log_line" /> | ||
<field | ||
name="groups" | ||
eval="[(4, ref('base.group_erp_manager')),(4, ref('auditlog.group_auditlog_manager'))]" | ||
/> | ||
<field name="domain_force">[(1, '=', 1)] | ||
</field> | ||
</record> | ||
hbrunn marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
</odoo> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
<?xml version="1.0" encoding="utf-8" ?> | ||
<odoo> | ||
<record id="group_can_view_audit_logs" model="res.groups"> | ||
<field name="name">View Audit Logs</field> | ||
</record> | ||
</odoo> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this group is not used anywhere and unnecessary given you'll assign groups in the access rules record I think? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @ntsirintanis The There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the rules from your legacy module should be deleted anyways, as you don't need them any more with this approach. for easier transition, mark them as noupdate in your legacy code, then those records won't be touched on module upgrade |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.