8000 Draft: [16.0][MIG] #10965 auditlog_security by KKamaa · Pull Request #3029 · OCA/server-tools · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

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

Open
wants to merge 11 commits into
base: 16.0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 98 additions & 0 deletions auditlog_security/README.rst
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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
by users belonging to specific views, while all other lines are allowed only to
by users belonging to specific groups, 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.
3 changes: 3 additions & 0 deletions auditlog_security/__init__.py
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
25 changes: 25 additions & 0 deletions auditlog_security/__manifest__.py
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,
}
6 changes: 6 additions & 0 deletions auditlog_security/models/__init__.py
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
25 changes: 25 additions & 0 deletions auditlog_security/models/auditlog_line_access_rule.py
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)
40 changes: 40 additions & 0 deletions auditlog_security/models/auditlog_log_line.py
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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ntsirintanis Typo readonly

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
model_id = fields.Many2one(related="log_id.model_id", store=True, reaonly=True)
model_id = fields.Many2one(related="log_id.model_id")

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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
rule_id = fields.Many2one("auditlog.rule", compute="_compute_rule_id", store=True)

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):
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)]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
domain = [("rule_id", "=", access_rule.auditlog_rule_id.id)]
domain = [("log_id.model_id", "=", access_rule.auditlog_rule_id.model_id.id)]

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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
@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)]
)

127 changes: 127 additions & 0 deletions auditlog_security/models/auditlog_rule.py
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"""
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
Copy link
Member

Choose a reason for hiding this comment

The 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,
}
)
)
self.write({"server_action_id": server_action.id})
return server_action

def subscribe(self):
for rule in self:
server_action = rule._create_server_action()
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()
1 change: 1 addition & 0 deletions auditlog_security/readme/CONTRIBUTORS.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* Giovanni Francesco Capalbo <giovanni@therp.nl>
Empty file.
3 changes: 3 additions & 0 deletions auditlog_security/readme/DESCRIPTION.rst
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.
1 change: 1 addition & 0 deletions auditlog_security/readme/ROADMAP.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

11 changes: 11 additions & 0 deletions auditlog_security/readme/USAGE.rst
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.
3 changes: 3 additions & 0 deletions auditlog_security/security/ir.model.access.csv
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
23 changes: 23 additions & 0 deletions auditlog_security/security/ir_rule.xml
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>

<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>

</odoo>
6 changes: 6 additions & 0 deletions auditlog_security/security/res_groups.xml
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>
Copy link
Member
@hbrunn hbrunn May 2, 2025

Choose a reason for hiding this comment

The 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?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ntsirintanis The View Audit Logs group is still being used in the Inuka instances.
Currently, it has around 11 users.
It's also being used in approx. 21 record rules.
This prevents to module from being upgraded.

Copy link
Member

Choose a reason for hiding this comment

The 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

Loading
Loading
0