[FIX-MOV] auth_totp, auth_totp_invite: move 2FA invite mail to new bridge module
Since 29db699e9b, auth_top depends of mail module, which lead to delay auth_totp
installation - not during DB creation anymore. As mail module is not installed
during DB creation, once an app that depends on mail is installed after DB
creation, auth_top module is finally installed and the session token now depends
auth_top module. As a result, the user is automatically logged out.
This commit moves the invite mail (and the dependance to 'mail' module) to a
new bridge module. Auth_totp module will now be reinstalled during DB creation
automatically.
Task-2638538
Parent Task-2487630
COM PR: odoo/odoo#76022
UPG PR: odoo/upgrade#2808
Signed-off-by: Thibault Delavallee (tde) <tde@openerp.com>
This commit is contained in:
@@ -14,14 +14,13 @@ Note: logically, two-factor prevents password-based RPC access for users
|
||||
where it is enabled. In order to be able to execute RPC scripts, the user
|
||||
can setup API keys to replace their main password.
|
||||
""",
|
||||
'depends': ['web', 'mail'],
|
||||
'depends': ['web'],
|
||||
'category': 'Extra Tools',
|
||||
'auto_install': True,
|
||||
'data': [
|
||||
'security/security.xml',
|
||||
'security/ir.model.access.csv',
|
||||
'data/ir_action_data.xml',
|
||||
'data/mail_template_data.xml',
|
||||
'views/res_users_views.xml',
|
||||
'views/templates.xml',
|
||||
'wizard/auth_totp_wizard_views.xml',
|
||||
|
||||
@@ -1,18 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<!-- Invite to user 2FA -->
|
||||
<record model="ir.actions.server" id="action_invite_totp">
|
||||
<field name="name">Invite to use two-factor authentication</field>
|
||||
<field name="model_id" ref="base.model_res_users"/>
|
||||
<field name="binding_model_id" ref="base.model_res_users"/>
|
||||
<field name="binding_view_types">list</field>
|
||||
<field name="state">code</field>
|
||||
<field name="code">
|
||||
action = records.action_totp_invite()
|
||||
</field>
|
||||
<field name="groups_id" eval="[(4, ref('base.group_erp_manager'))]"/>
|
||||
</record>
|
||||
|
||||
<!-- Action called from the contextual menu -->
|
||||
<record model="ir.actions.server" id="action_disable_totp">
|
||||
<field name="name">Disable two-factor authentication</field>
|
||||
@@ -25,16 +12,4 @@
|
||||
</field>
|
||||
<field name="groups_id" eval="[(4, ref('base.group_erp_manager'))]"/>
|
||||
</record>
|
||||
|
||||
<!--Action called when using the link in "Invite to use 2FA" mail-->
|
||||
<record model="ir.actions.server" id="action_activate_two_factor_authentication">
|
||||
<field name="name">Open two-factor authentication configuration</field>
|
||||
<field name="model_id" ref="base.model_res_users"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">
|
||||
user = env.user
|
||||
action = user.action_open_my_account_settings()
|
||||
</field>
|
||||
<field name="groups_id" eval="[(4, ref('base.group_user'))]"/>
|
||||
</record>
|
||||
</odoo>
|
||||
|
||||
@@ -41,16 +41,6 @@ class Users(models.Model):
|
||||
for r, v in zip(self, self.sudo()):
|
||||
r.totp_enabled = bool(v.totp_secret)
|
||||
|
||||
def action_open_my_account_settings(self):
|
||||
action = {
|
||||
"name": _("Account Security"),
|
||||
"type": "ir.actions.act_window",
|
||||
"res_model": "res.users",
|
||||
"views": [[self.env.ref('auth_totp.res_users_view_form_security').id, "form"]],
|
||||
"res_id": self.id,
|
||||
}
|
||||
return action
|
||||
|
||||
def _rpc_api_keys_only(self):
|
||||
# 2FA enabled means we can't allow password-based RPC
|
||||
self.ensure_one()
|
||||
@@ -89,32 +79,6 @@ class Users(models.Model):
|
||||
_logger.info("2FA enable: SUCCESS for %s %r", self, self.login)
|
||||
return True
|
||||
|
||||
def get_totp_invite_url(self):
|
||||
return '/web#action=auth_totp.action_activate_two_factor_authentication'
|
||||
|
||||
def action_totp_invite(self):
|
||||
invite_template = self.env.ref('auth_totp.mail_template_totp_invite')
|
||||
users_to_invite = self.sudo().filtered(lambda user: not user.totp_secret)
|
||||
for user in users_to_invite:
|
||||
email_values = {
|
||||
'email_from': self.env.user.email_formatted,
|
||||
'author_id': self.env.user.partner_id.id,
|
||||
}
|
||||
invite_template.send_mail(user.id, force_send=True, email_values=email_values,
|
||||
notif_layout='mail.mail_notification_light')
|
||||
|
||||
# Display a confirmation toaster
|
||||
return {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'display_notification',
|
||||
'params': {
|
||||
'type': 'info',
|
||||
'sticky': False,
|
||||
'message': _("Invitation to use two-factor authentication sent for the following user(s): %s",
|
||||
', '.join(users_to_invite.mapped('name'))),
|
||||
}
|
||||
}
|
||||
|
||||
@check_identity
|
||||
def action_totp_disable(self):
|
||||
logins = ', '.join(map(repr, self.mapped('login')))
|
||||
|
||||
@@ -31,8 +31,6 @@
|
||||
disabled="1" type="object" class="fa fa-toggle-off o_auth_2fa_btn disabled" aria-label="Enable 2FA"></button>
|
||||
<button attrs="{'invisible': "[('id', '!=', uid)]"}" name="action_totp_enable_wizard"
|
||||
type="object" class="fa fa-toggle-off o_auth_2fa_btn disabled" aria-label="Enable 2FA"></button>
|
||||
<button groups="base.group_erp_manager" attrs="{'invisible': "[('id', '=', uid)]"}"
|
||||
name="action_totp_invite" string="Invite to use 2FA" type="object" class="btn btn-secondary"></button>
|
||||
</div>
|
||||
<button attrs="{'invisible': [('totp_enabled', '=', False)]}" name="action_totp_disable" type="object"
|
||||
class="fa fa-toggle-on o_auth_2fa_btn text-primary enabled" aria-label="Disable 2FA"></button>
|
||||
@@ -105,36 +103,4 @@
|
||||
</group>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- View used when coming from "invite to use 2FA" mail -->
|
||||
<record model="ir.ui.view" id="res_users_view_form_security">
|
||||
<field name="name">users preference: Account Security</field>
|
||||
<field name="model">res.users</field>
|
||||
<field name="inherit_id" ref="base.view_users_form_simple_modif"/>
|
||||
<field name="mode">primary</field>
|
||||
<field name="arch" type="xml">
|
||||
<form position="attributes">
|
||||
<attribute name='create'>0</attribute>
|
||||
<attribute name='edit'>0</attribute>
|
||||
<attribute name='delete'>0</attribute>
|
||||
</form>
|
||||
<h1 position="replace"/>
|
||||
<xpath expr="//field[@name='image_1920']" position="replace"/>
|
||||
<notebook position="replace">
|
||||
<header>
|
||||
</header>
|
||||
<sheet>$0</sheet>
|
||||
</notebook>
|
||||
<notebook position="before">
|
||||
<field name="image_1920" widget="image" class="oe_avatar" options="{'zoom': true, 'preview_image':'image_128'}"/>
|
||||
<div class="oe_title">
|
||||
<h1>
|
||||
<field name="name" placeholder="Name" required="True" readonly="context.get('from_my_profile', False)"/>
|
||||
</h1>
|
||||
</div>
|
||||
</notebook>
|
||||
<page name="preferences_page" position="replace"></page>
|
||||
<footer position="replace"/>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import models
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
'name': '2FA Invite mail',
|
||||
'description': """
|
||||
2FA Invite mail
|
||||
===============
|
||||
Allow the users to invite another user to use Two-Factor authentication
|
||||
by sending an email to the target user. This email redirect him to :
|
||||
- the users security settings if the user is internal.
|
||||
- the portal security settings page if the user is not internal.
|
||||
""",
|
||||
'depends': ['auth_totp', 'mail'],
|
||||
'category': 'Extra Tools',
|
||||
'auto_install': True,
|
||||
'data': [
|
||||
'data/ir_action_data.xml',
|
||||
'data/mail_template_data.xml',
|
||||
'views/res_users_views.xml',
|
||||
],
|
||||
'assets': {},
|
||||
'license': 'LGPL-3',
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<!-- Invite to user 2FA -->
|
||||
<record model="ir.actions.server" id="action_invite_totp">
|
||||
<field name="name">Invite to use two-factor authentication</field>
|
||||
<field name="model_id" ref="base.model_res_users"/>
|
||||
<field name="binding_model_id" ref="base.model_res_users"/>
|
||||
<field name="binding_view_types">list</field>
|
||||
<field name="state">code</field>
|
||||
<field name="code">
|
||||
action = records.action_totp_invite()
|
||||
</field>
|
||||
<field name="groups_id" eval="[(4, ref('base.group_erp_manager'))]"/>
|
||||
</record>
|
||||
|
||||
<!--Action called when using the link in "Invite to use 2FA" mail-->
|
||||
<record model="ir.actions.server" id="action_activate_two_factor_authentication">
|
||||
<field name="name">Open two-factor authentication configuration</field>
|
||||
<field name="model_id" ref="base.model_res_users"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">
|
||||
user = env.user
|
||||
action = user.action_open_my_account_settings()
|
||||
</field>
|
||||
<field name="groups_id" eval="[(4, ref('base.group_user'))]"/>
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -0,0 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import res_users
|
||||
@@ -0,0 +1,44 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import _, models
|
||||
|
||||
|
||||
class Users(models.Model):
|
||||
_inherit = 'res.users'
|
||||
|
||||
def action_open_my_account_settings(self):
|
||||
action = {
|
||||
"name": _("Account Security"),
|
||||
"type": "ir.actions.act_window",
|
||||
"res_model": "res.users",
|
||||
"views": [[self.env.ref('auth_totp_mail.res_users_view_form').id, "form"]],
|
||||
"res_id": self.id,
|
||||
}
|
||||
return action
|
||||
|
||||
def get_totp_invite_url(self):
|
||||
return '/web#action=auth_totp_mail.action_activate_two_factor_authentication'
|
||||
|
||||
def action_totp_invite(self):
|
||||
invite_template = self.env.ref('auth_totp_mail.mail_template_totp_invite')
|
||||
users_to_invite = self.sudo().filtered(lambda user: not user.totp_secret)
|
||||
for user in users_to_invite:
|
||||
email_values = {
|
||||
'email_from': self.env.user.email_formatted,
|
||||
'author_id': self.env.user.partner_id.id,
|
||||
}
|
||||
invite_template.send_mail(user.id, force_send=True, email_values=email_values,
|
||||
notif_layout='mail.mail_notification_light')
|
||||
|
||||
# Display a confirmation toaster
|
||||
return {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'display_notification',
|
||||
'params': {
|
||||
'type': 'info',
|
||||
'sticky': False,
|
||||
'message': _("Invitation to use two-factor authentication sent for the following user(s): %s",
|
||||
', '.join(users_to_invite.mapped('name'))),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record model="ir.ui.view" id="view_users_form">
|
||||
<field name="name">res.users.view.form.inherit.auth.totp.mail</field>
|
||||
<field name="model">res.users</field>
|
||||
<field name="inherit_id" ref="base.view_users_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//button[@name='action_totp_enable_wizard']" position="after">
|
||||
<button groups="base.group_erp_manager" attrs="{'invisible': "[('id', '=', uid)]"}"
|
||||
name="action_totp_invite" string="Invite to use 2FA" type="object" class="btn btn-secondary"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- View used when coming from "invite to use 2FA" mail -->
|
||||
<record model="ir.ui.view" id="auth_totp_mail.res_users_view_form">
|
||||
<field name="name">res.users.view.form.auth.totp.mail</field>
|
||||
<field name="model">res.users</field>
|
||||
<field name="inherit_id" ref="base.view_users_form_simple_modif"/>
|
||||
<field name="mode">primary</field>
|
||||
<field name="arch" type="xml">
|
||||
<form position="attributes">
|
||||
<attribute name='create'>0</attribute>
|
||||
<attribute name='edit'>0</attribute>
|
||||
<attribute name='delete'>0</attribute>
|
||||
</form>
|
||||
<h1 position="replace"/>
|
||||
<xpath expr="//field[@name='image_1920']" position="replace"/>
|
||||
<notebook position="replace">
|
||||
<header>
|
||||
</header>
|
||||
<sheet>$0</sheet>
|
||||
</notebook>
|
||||
<notebook position="before">
|
||||
<field name="image_1920" widget="image" class="oe_avatar" options="{'zoom': true, 'preview_image':'image_128'}"/>
|
||||
<div class="oe_title">
|
||||
<h1>
|
||||
<field name="name" placeholder="Name" required="True" readonly="context.get('from_my_profile', False)"/>
|
||||
</h1>
|
||||
</div>
|
||||
</notebook>
|
||||
<page name="preferences_page" position="replace"></page>
|
||||
<footer position="replace"/>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
Reference in New Issue
Block a user