From b875e4add1d2c374d5f4caf76a347e5fd9e373a5 Mon Sep 17 00:00:00 2001 From: Florent THOMAS Date: Sat, 23 Dec 2023 22:55:38 +0100 Subject: [PATCH 01/45] [DOC]Add option to configure --- auth_oidc/readme/CONFIGURE.md | 1 + 1 file changed, 1 insertion(+) diff --git a/auth_oidc/readme/CONFIGURE.md b/auth_oidc/readme/CONFIGURE.md index 275e4c0a20..72c032e94c 100644 --- a/auth_oidc/readme/CONFIGURE.md +++ b/auth_oidc/readme/CONFIGURE.md @@ -57,6 +57,7 @@ In Odoo, create a new Oauth Provider with the following parameters: - Provider name: Keycloak (or any name you like that identify your keycloak provider) - Auth Flow: OpenID Connect (authorization code flow) +- Token Map : `preferred_username:user_id` - Client ID: the same Client ID you entered when configuring the client in Keycloak - Client Secret: found in keycloak on the client Credentials tab From 21b32eac4d0172c3023498df369a67d0fc997521 Mon Sep 17 00:00:00 2001 From: Florent THOMAS Date: Mon, 25 Dec 2023 19:49:54 +0100 Subject: [PATCH 02/45] [DOC]auth_oidc: more options for token maps --- auth_oidc/readme/CONFIGURE.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/auth_oidc/readme/CONFIGURE.md b/auth_oidc/readme/CONFIGURE.md index 72c032e94c..9796089fd5 100644 --- a/auth_oidc/readme/CONFIGURE.md +++ b/auth_oidc/readme/CONFIGURE.md @@ -57,7 +57,8 @@ In Odoo, create a new Oauth Provider with the following parameters: - Provider name: Keycloak (or any name you like that identify your keycloak provider) - Auth Flow: OpenID Connect (authorization code flow) -- Token Map : `preferred_username:user_id` +- Token Map : many options are possible like `preferred_username:user_id` or + `email:user_id` . This can be combined - Client ID: the same Client ID you entered when configuring the client in Keycloak - Client Secret: found in keycloak on the client Credentials tab From 6078367b37609aa29c7ffba97ee7c5e95c54ef6e Mon Sep 17 00:00:00 2001 From: Janik von Rotz Date: Tue, 14 May 2024 16:39:54 +0200 Subject: [PATCH 03/45] Fix: move tenant id config step in readme --- auth_oidc/readme/CONFIGURE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/auth_oidc/readme/CONFIGURE.md b/auth_oidc/readme/CONFIGURE.md index 8145f4faf9..6e25411908 100644 --- a/auth_oidc/readme/CONFIGURE.md +++ b/auth_oidc/readme/CONFIGURE.md @@ -27,6 +27,7 @@ companies can use their AzureAD login without an guest account. - Client ID: Application (client) id - Client Secret: Client secret - Allowed: yes +- replace {tenant_id} in urls with your Azure tenant id or @@ -34,7 +35,6 @@ or - Client ID: Application (client) id - Client Secret: Client secret - Allowed: yes -- replace {tenant_id} in urls with your Azure tenant id ![image](../static/description/odoo-azure_ad_multitenant.png) From 149eba7d77c31019e9d058469050c35736d79bc9 Mon Sep 17 00:00:00 2001 From: mymage Date: Sat, 17 Aug 2024 16:16:53 +0000 Subject: [PATCH 04/45] Translated using Weblate (Italian) Currently translated at 100.0% (18 of 18 strings) Translation: server-auth-16.0/server-auth-16.0-auth_api_key Translate-URL: https://translation.odoo-community.org/projects/server-auth-16-0/server-auth-16-0-auth_api_key/it/ --- auth_api_key/i18n/it.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/auth_api_key/i18n/it.po b/auth_api_key/i18n/it.po index 47a977a578..2be7830419 100644 --- a/auth_api_key/i18n/it.po +++ b/auth_api_key/i18n/it.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: Odoo Server 15.0\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2024-07-18 06:52+0000\n" +"PO-Revision-Date: 2024-08-17 18:58+0000\n" "Last-Translator: mymage \n" "Language-Team: none\n" "Language: it\n" @@ -40,7 +40,7 @@ msgstr "Creato da" #. module: auth_api_key #: model:ir.model.fields,field_description:auth_api_key.field_auth_api_key__create_date msgid "Created on" -msgstr "Creata il" +msgstr "Creato il" #. module: auth_api_key #: model:ir.model.fields,field_description:auth_api_key.field_auth_api_key__display_name From 98a33a34a12360b03a93b696e33bbeb480e418c3 Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Sun, 18 Aug 2024 12:23:30 +0000 Subject: [PATCH 05/45] [BOT] post-merge updates --- README.md | 2 +- auth_oidc/README.rst | 4 ++-- auth_oidc/__manifest__.py | 2 +- auth_oidc/static/description/index.html | 15 +++++++++------ 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 52150fcd07..819c5ac48a 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ addon | version | maintainers | summary [auth_ldaps](auth_ldaps/) | 16.0.1.0.0 | | Allows to use LDAP over SSL authentication [auth_oauth_multi_token](auth_oauth_multi_token/) | 16.0.1.0.0 | | Allow multiple connection with the same OAuth account [auth_oauth_ropc](auth_oauth_ropc/) | 16.0.1.0.0 | | Allow to login with OAuth Resource Owner Password Credentials Grant -[auth_oidc](auth_oidc/) | 16.0.1.2.0 | [![sbidoul](https://github.com/sbidoul.png?size=30px)](https://github.com/sbidoul) | Allow users to login through OpenID Connect Provider +[auth_oidc](auth_oidc/) | 16.0.1.2.1 | [![sbidoul](https://github.com/sbidoul.png?size=30px)](https://github.com/sbidoul) | Allow users to login through OpenID Connect Provider [auth_oidc_environment](auth_oidc_environment/) | 16.0.1.0.0 | | This module allows to use server env for OIDC configuration [auth_saml](auth_saml/) | 16.0.1.1.0 | [![vincent-hatakeyama](https://github.com/vincent-hatakeyama.png?size=30px)](https://github.com/vincent-hatakeyama) | SAML2 Authentication [auth_session_timeout](auth_session_timeout/) | 16.0.1.0.0 | | This module disable all inactive sessions since a given delay diff --git a/auth_oidc/README.rst b/auth_oidc/README.rst index 495caa673b..cbcd525dc2 100644 --- a/auth_oidc/README.rst +++ b/auth_oidc/README.rst @@ -7,7 +7,7 @@ Authentication OpenID Connect !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:0fa6d13be474eeb0ba5716895f4fc42ded1b84285279efbe29a476cead7e5565 + !! source digest: sha256:0151be3fa09ed3535a518b36fbf8bd9fa122f56d84180c1bc79a14ab9792dbbe !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png @@ -79,6 +79,7 @@ companies can use their AzureAD login without an guest account. - Client ID: Application (client) id - Client Secret: Client secret - Allowed: yes +- replace {tenant_id} in urls with your Azure tenant id or @@ -86,7 +87,6 @@ or - Client ID: Application (client) id - Client Secret: Client secret - Allowed: yes -- replace {tenant_id} in urls with your Azure tenant id |image2| diff --git a/auth_oidc/__manifest__.py b/auth_oidc/__manifest__.py index df9bdaac8a..3f1abf0c1d 100644 --- a/auth_oidc/__manifest__.py +++ b/auth_oidc/__manifest__.py @@ -4,7 +4,7 @@ { "name": "Authentication OpenID Connect", - "version": "16.0.1.2.0", + "version": "16.0.1.2.1", "license": "AGPL-3", "author": ( "ICTSTUDIO, André Schenkels, " diff --git a/auth_oidc/static/description/index.html b/auth_oidc/static/description/index.html index 46ba91854f..6b5283b2ed 100644 --- a/auth_oidc/static/description/index.html +++ b/auth_oidc/static/description/index.html @@ -8,10 +8,11 @@ /* :Author: David Goodger (goodger@python.org) -:Id: $Id: html4css1.css 8954 2022-01-20 10:10:25Z milde $ +:Id: $Id: html4css1.css 9511 2024-01-13 09:50:07Z milde $ :Copyright: This stylesheet has been placed in the public domain. Default cascading style sheet for the HTML output of Docutils. +Despite the name, some widely supported CSS2 features are used. See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to customize this style sheet. @@ -274,7 +275,7 @@ margin-left: 2em ; margin-right: 2em } -pre.code .ln { color: grey; } /* line numbers */ +pre.code .ln { color: gray; } /* line numbers */ pre.code, code { background-color: #eeeeee } pre.code .comment, code .comment { color: #5C6576 } pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold } @@ -300,7 +301,7 @@ span.pre { white-space: pre } -span.problematic { +span.problematic, pre.problematic { color: red } span.section-subtitle { @@ -366,7 +367,7 @@

Authentication OpenID Connect

!! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!! source digest: sha256:0fa6d13be474eeb0ba5716895f4fc42ded1b84285279efbe29a476cead7e5565 +!! source digest: sha256:0151be3fa09ed3535a518b36fbf8bd9fa122f56d84180c1bc79a14ab9792dbbe !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->

Beta License: AGPL-3 OCA/server-auth Translate me on Weblate Try me on Runboat

This module allows users to login through an OpenID Connect provider @@ -437,6 +438,7 @@

Setup for Microsoft Azure

Client ID: Application (client) id
  • Client Secret: Client secret
  • Allowed: yes
  • +
  • replace {tenant_id} in urls with your Azure tenant id
  • or

      @@ -444,7 +446,6 @@

      Setup for Microsoft Azure

      Client ID: Application (client) id
    • Client Secret: Client secret
    • Allowed: yes
    • -
    • replace {tenant_id} in urls with your Azure tenant id

    image2

      @@ -579,7 +580,9 @@

      Contributors

      Maintainers

      This module is maintained by the OCA.

      -Odoo Community Association + +Odoo Community Association +

      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.

      From 9feb331eb9c76edc1849341c806783dc199aaa12 Mon Sep 17 00:00:00 2001 From: Carlos Roca Date: Tue, 20 Aug 2024 07:49:47 +0200 Subject: [PATCH 06/45] [FIX] vault_share: Button to share value not showed and not working To show the button up, it is requiring a getter that is not defined on vault field. So the getter is added and make the button works correctly. Steps to reproduce the problem: 1. Go to Vault 2. Enter/Create a Vault 3. Press on entries 4. Access/Create a entry with a field The button with external link is not showed --- vault_share/static/src/backend/fields/vault_field.esm.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/vault_share/static/src/backend/fields/vault_field.esm.js b/vault_share/static/src/backend/fields/vault_field.esm.js index 57190388cb..574c1075c4 100644 --- a/vault_share/static/src/backend/fields/vault_field.esm.js +++ b/vault_share/static/src/backend/fields/vault_field.esm.js @@ -11,18 +11,22 @@ import vault from "vault"; // Extend the widget to share patch(VaultField.prototype, "vault_share", { + get shareButton() { + return this.props.value; + }, /** * Share the value for an external user * * @private */ - async _onShareValue() { + async _onShareValue(ev) { + ev.stopPropagation(); const iv = await utils.generate_iv_base64(); const pin = sh_utils.generate_pin(sh_utils.PinSize); const salt = utils.generate_bytes(utils.SaltLength).buffer; const key = await utils.derive_key(pin, salt, utils.Derive.iterations); const public_key = await vault.get_public_key(); - const value = await this._decrypt(this.value); + const value = await this._decrypt(this.props.value); this.action.doAction({ type: "ir.actions.act_window", From 2f13bb5260a3e7b76a093146ef3dce6150f9dab2 Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Tue, 20 Aug 2024 06:13:16 +0000 Subject: [PATCH 07/45] [BOT] post-merge updates --- README.md | 2 +- vault_share/README.rst | 2 +- vault_share/__manifest__.py | 2 +- vault_share/static/description/index.html | 13 ++++++++----- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 819c5ac48a..637323ce37 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ addon | version | maintainers | summary [users_ldap_mail](users_ldap_mail/) | 16.0.1.0.0 | [![joao-p-marques](https://github.com/joao-p-marques.png?size=30px)](https://github.com/joao-p-marques) | LDAP mapping for user name and e-mail [users_ldap_populate](users_ldap_populate/) | 16.0.1.0.0 | [![joao-p-marques](https://github.com/joao-p-marques.png?size=30px)](https://github.com/joao-p-marques) | LDAP Populate [vault](vault/) | 16.0.1.0.3 | | Password vault integration in Odoo -[vault_share](vault_share/) | 16.0.1.0.0 | | Implementation of a mechanism to share secrets +[vault_share](vault_share/) | 16.0.1.0.1 | | Implementation of a mechanism to share secrets [//]: # (end addons) diff --git a/vault_share/README.rst b/vault_share/README.rst index 69390742a5..474f260840 100644 --- a/vault_share/README.rst +++ b/vault_share/README.rst @@ -7,7 +7,7 @@ Vault - Share !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:adce488b82d4097f6a7f94b8dfeb82712b9e717846f3cc745600419fc4393eed + !! source digest: sha256:4f783283b6bf81c2c6575a505ca9e6d9f5d0ea120a8c48b2d2921596e51956f6 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png diff --git a/vault_share/__manifest__.py b/vault_share/__manifest__.py index 7e05ea658a..ca57451111 100644 --- a/vault_share/__manifest__.py +++ b/vault_share/__manifest__.py @@ -5,7 +5,7 @@ "name": "Vault - Share", "summary": "Implementation of a mechanism to share secrets", "license": "AGPL-3", - "version": "16.0.1.0.0", + "version": "16.0.1.0.1", "website": "https://github.com/OCA/server-auth", "application": False, "author": "initOS GmbH, Odoo Community Association (OCA)", diff --git a/vault_share/static/description/index.html b/vault_share/static/description/index.html index 29d5221c0d..c537ea1195 100644 --- a/vault_share/static/description/index.html +++ b/vault_share/static/description/index.html @@ -8,10 +8,11 @@ /* :Author: David Goodger (goodger@python.org) -:Id: $Id: html4css1.css 8954 2022-01-20 10:10:25Z milde $ +:Id: $Id: html4css1.css 9511 2024-01-13 09:50:07Z milde $ :Copyright: This stylesheet has been placed in the public domain. Default cascading style sheet for the HTML output of Docutils. +Despite the name, some widely supported CSS2 features are used. See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to customize this style sheet. @@ -274,7 +275,7 @@ margin-left: 2em ; margin-right: 2em } -pre.code .ln { color: grey; } /* line numbers */ +pre.code .ln { color: gray; } /* line numbers */ pre.code, code { background-color: #eeeeee } pre.code .comment, code .comment { color: #5C6576 } pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold } @@ -300,7 +301,7 @@ span.pre { white-space: pre } -span.problematic { +span.problematic, pre.problematic { color: red } span.section-subtitle { @@ -366,7 +367,7 @@

      Vault - Share

      !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!! source digest: sha256:adce488b82d4097f6a7f94b8dfeb82712b9e717846f3cc745600419fc4393eed +!! source digest: sha256:4f783283b6bf81c2c6575a505ca9e6d9f5d0ea120a8c48b2d2921596e51956f6 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->

      Beta License: AGPL-3 OCA/server-auth Translate me on Weblate Try me on Runboat

      This module implements possibilities to share specific secrets with external users. This bases on the vault implementation and the generated RSA key pair.

      @@ -414,7 +415,9 @@

      Contributors

      Maintainers

      This module is maintained by the OCA.

      -Odoo Community Association + +Odoo Community Association +

      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.

      From 58472e1a9c599ded5b8c496f8084fc704e2615df Mon Sep 17 00:00:00 2001 From: Kev-Roche Date: Tue, 14 May 2024 09:54:25 +0200 Subject: [PATCH 08/45] [14.0][ADD] impersonate_login --- impersonate_login/README.rst | 96 ++++ impersonate_login/__init__.py | 1 + impersonate_login/__manifest__.py | 30 ++ impersonate_login/models/__init__.py | 6 + impersonate_login/models/impersonate_log.py | 26 ++ impersonate_login/models/ir_http.py | 20 + impersonate_login/models/mail_message.py | 52 +++ impersonate_login/models/mail_thread.py | 30 ++ impersonate_login/models/model.py | 24 + impersonate_login/models/res_users.py | 87 ++++ impersonate_login/readme/CONTRIBUTORS.rst | 1 + impersonate_login/readme/DESCRIPTION.rst | 7 + impersonate_login/readme/USAGE.rst | 2 + impersonate_login/security/group.xml | 13 + .../security/ir.model.access.csv | 2 + .../static/description/index.html | 437 ++++++++++++++++++ impersonate_login/static/src/css/navbar.scss | 23 + .../static/src/js/abstract_web_client.js | 18 + impersonate_login/static/src/js/user_menu.js | 66 +++ .../static/src/xml/user_menu.xml | 22 + impersonate_login/views/assets.xml | 24 + impersonate_login/views/impersonate_log.xml | 36 ++ impersonate_login/views/res_users.xml | 22 + 23 files changed, 1045 insertions(+) create mode 100644 impersonate_login/README.rst create mode 100644 impersonate_login/__init__.py create mode 100644 impersonate_login/__manifest__.py create mode 100644 impersonate_login/models/__init__.py create mode 100644 impersonate_login/models/impersonate_log.py create mode 100644 impersonate_login/models/ir_http.py create mode 100644 impersonate_login/models/mail_message.py create mode 100644 impersonate_login/models/mail_thread.py create mode 100644 impersonate_login/models/model.py create mode 100644 impersonate_login/models/res_users.py create mode 100644 impersonate_login/readme/CONTRIBUTORS.rst create mode 100644 impersonate_login/readme/DESCRIPTION.rst create mode 100644 impersonate_login/readme/USAGE.rst create mode 100644 impersonate_login/security/group.xml create mode 100644 impersonate_login/security/ir.model.access.csv create mode 100644 impersonate_login/static/description/index.html create mode 100644 impersonate_login/static/src/css/navbar.scss create mode 100644 impersonate_login/static/src/js/abstract_web_client.js create mode 100644 impersonate_login/static/src/js/user_menu.js create mode 100644 impersonate_login/static/src/xml/user_menu.xml create mode 100644 impersonate_login/views/assets.xml create mode 100644 impersonate_login/views/impersonate_log.xml create mode 100644 impersonate_login/views/res_users.xml diff --git a/impersonate_login/README.rst b/impersonate_login/README.rst new file mode 100644 index 0000000000..5df334246f --- /dev/null +++ b/impersonate_login/README.rst @@ -0,0 +1,96 @@ +================= +Impersonate Login +================= + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:1fca331cbc5f2dcb804e5612e5669a9ab4998d80f22d46d6683266580f9ca40f + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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--auth-lightgray.png?logo=github + :target: https://github.com/OCA/server-auth/tree/14.0/impersonate_login + :alt: OCA/server-auth +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/server-auth-14-0/server-auth-14-0-impersonate_login + :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-auth&target_branch=14.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module allows to login as another user. +In the chatter, the user who is logged as another user is displayed. +The mails and messages are sent from the orignal user. +A table diplays the impersonated logins in technical. +The user can return to his own user by clicking on the button "Return to my user". +This module is very useful for the support team. +An alternative module will be auth_admin_passkey. + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +1. On the top right corner, click my user and "switch login" +2. Same place to "return to my login" + +Bug Tracker +=========== + +Bugs are tracked on `GitHub 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 `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* Akretion + +Contributors +~~~~~~~~~~~~ + +* Kévin Roche + +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. + +.. |maintainer-Kev-Roche| image:: https://github.com/Kev-Roche.png?size=40px + :target: https://github.com/Kev-Roche + :alt: Kev-Roche + +Current `maintainer `__: + +|maintainer-Kev-Roche| + +This module is part of the `OCA/server-auth `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/impersonate_login/__init__.py b/impersonate_login/__init__.py new file mode 100644 index 0000000000..0650744f6b --- /dev/null +++ b/impersonate_login/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/impersonate_login/__manifest__.py b/impersonate_login/__manifest__.py new file mode 100644 index 0000000000..61c00eb90e --- /dev/null +++ b/impersonate_login/__manifest__.py @@ -0,0 +1,30 @@ +# Copyright 2024 Akretion (https://www.akretion.com). +# @author Kévin Roche +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +{ + "name": "Impersonate Login", + "summary": "tools", + "version": "14.0.1.0.0", + "category": "Tools", + "website": "https://github.com/OCA/server-auth", + "author": "Akretion, Odoo Community Association (OCA)", + "maintainers": ["Kev-Roche"], + "license": "AGPL-3", + "application": False, + "installable": True, + "depends": [ + "web", + "mail", + ], + "data": [ + "views/assets.xml", + "views/res_users.xml", + "views/impersonate_log.xml", + "security/group.xml", + "security/ir.model.access.csv", + ], + "qweb": [ + "static/src/xml/user_menu.xml", + ], +} diff --git a/impersonate_login/models/__init__.py b/impersonate_login/models/__init__.py new file mode 100644 index 0000000000..debb66e9c1 --- /dev/null +++ b/impersonate_login/models/__init__.py @@ -0,0 +1,6 @@ +from . import res_users +from . import ir_http +from . import mail_thread +from . import mail_message +from . import impersonate_log +from . import model diff --git a/impersonate_login/models/impersonate_log.py b/impersonate_login/models/impersonate_log.py new file mode 100644 index 0000000000..31ab131f63 --- /dev/null +++ b/impersonate_login/models/impersonate_log.py @@ -0,0 +1,26 @@ +# Copyright (C) 2024 Akretion (). +# @author Kévin Roche +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + + +from odoo import fields, models + + +class ImpersonateLog(models.Model): + _name = "impersonate.log" + _description = "Impersonate Logs" + + user_id = fields.Many2one( + comodel_name="res.partner", + string="User", + ) + impersonated_partner_id = fields.Many2one( + comodel_name="res.partner", + string="Logged as", + ) + date_start = fields.Datetime( + string="Start Date", + ) + date_end = fields.Datetime( + string="End Date", + ) diff --git a/impersonate_login/models/ir_http.py b/impersonate_login/models/ir_http.py new file mode 100644 index 0000000000..f01aa613d2 --- /dev/null +++ b/impersonate_login/models/ir_http.py @@ -0,0 +1,20 @@ +# Copyright (C) 2024 Akretion (). +# @author Kévin Roche +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import models +from odoo.http import request + + +class Http(models.AbstractModel): + _inherit = "ir.http" + + def session_info(self): + session_info = super().session_info() + session_info.update( + { + "is_impersonate_user": request.env.user._is_impersonate_user(), + "impersonate_from_uid": request.session.impersonate_from_uid, + } + ) + return session_info diff --git a/impersonate_login/models/mail_message.py b/impersonate_login/models/mail_message.py new file mode 100644 index 0000000000..332d117ee3 --- /dev/null +++ b/impersonate_login/models/mail_message.py @@ -0,0 +1,52 @@ +# Copyright (C) 2024 Akretion (). +# @author Kévin Roche +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import _, api, fields, models +from odoo.http import request + + +class Message(models.Model): + _inherit = "mail.message" + + impersonated_author_id = fields.Many2one( + comodel_name="res.partner", + string="Impersonated Author", + compute="_compute_impersonated_author_id", + store=True, + ) + + body = fields.Html( + compute="_compute_message_body", + store=True, + ) + + @api.depends("author_id") + def _compute_impersonated_author_id(self): + for rec in self: + if request and request.session.impersonate_from_uid: + rec.impersonated_author_id = ( + self.env["res.users"] + .browse(request.session.impersonate_from_uid) + .partner_id.id + ) + else: + rec.impersonated_author_id = False + + @api.depends("author_id", "impersonated_author_id") + def _compute_message_body(self): + for rec in self: + additional_info = "" + if ( + request + and request.session.impersonate_from_uid + and rec.impersonated_author_id + ): + current_partner = ( + self.env["res.users"].browse(request.session.uid).partner_id + ) + additional_info = _(f"Logged as {current_partner.name}") + if rec.body and additional_info: + rec.body = f"{additional_info}
      {rec.body}" + else: + rec.body = additional_info diff --git a/impersonate_login/models/mail_thread.py b/impersonate_login/models/mail_thread.py new file mode 100644 index 0000000000..1c1f80da83 --- /dev/null +++ b/impersonate_login/models/mail_thread.py @@ -0,0 +1,30 @@ +# Copyright (C) 2024 Akretion (). +# @author Kévin Roche +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import models +from odoo.http import request + + +class MailThread(models.AbstractModel): + _inherit = "mail.thread" + + def _message_compute_author( + self, author_id=None, email_from=None, raise_exception=True + ): + if ( + request + and request.session.impersonate_from_uid + and author_id in [request.session.uid, None] + ): + author = ( + self.env["res.users"] + .browse(request.session.impersonate_from_uid) + .partner_id + ) + email = author.email_formatted + return author.id, email + else: + return super()._message_compute_author( + author_id, email_from, raise_exception + ) diff --git a/impersonate_login/models/model.py b/impersonate_login/models/model.py new file mode 100644 index 0000000000..61f6e6655d --- /dev/null +++ b/impersonate_login/models/model.py @@ -0,0 +1,24 @@ +# Copyright (C) 2024 Akretion (). +# @author Kévin Roche +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import api, models +from odoo.http import request + + +class BaseModel(models.AbstractModel): + _inherit = "base" + + @api.model_create_multi + def _create(self, data_list): + res = super()._create(data_list) + if request and request.session.impersonate_from_uid: + for rec in res: + rec.create_uid = request.session.impersonate_from_uid + return res + + def write(self, vals): + res = super().write(vals) + if request and request.session.impersonate_from_uid: + self.write_uid = request.session.impersonate_from_uid + return res diff --git a/impersonate_login/models/res_users.py b/impersonate_login/models/res_users.py new file mode 100644 index 0000000000..f7e8cea4b0 --- /dev/null +++ b/impersonate_login/models/res_users.py @@ -0,0 +1,87 @@ +# Copyright 2024 Akretion (https://www.akretion.com). +# @author Kévin Roche +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +import logging + +from odoo import _, api, fields, models +from odoo.exceptions import UserError +from odoo.http import request +from odoo.service import security + +logger = logging.getLogger(__name__) + + +class Users(models.Model): + _inherit = "res.users" + + def _get_partner_name(self, user_id): + return self.env["res.users"].browse(user_id).partner_id.name + + def _is_impersonate_user(self): + self.ensure_one() + return self.has_group("impersonate_login.group_impersonate_login") + + def impersonate_login(self): + if request: + if request.session.impersonate_from_uid: + raise UserError(_("You are already Logged as another user.")) + if self.id == request.session.uid: + raise UserError(_("It's you.")) + if request.env.user._is_impersonate_user(): + target_uid = self.id + request.session.impersonate_from_uid = self._uid + request.session.uid = target_uid + impersonate_log = ( + self.env["impersonate.log"] + .sudo() + .create( + { + "user_id": self.env["res.users"] + .browse(self._uid) + .partner_id.id, + "impersonated_partner_id": self.env["res.users"] + .browse(target_uid) + .partner_id.id, + "date_start": fields.datetime.now(), + } + ) + ) + request.session.impersonate_log_id = impersonate_log.id + logger.info( + f"IMPERSONATE: {self._get_partner_name(self._uid)} " + f"Login as {self._get_partner_name(self.id)}" + ) + + request.env["res.users"].clear_caches() + request.session.session_token = security.compute_session_token( + request.session, request.env + ) + return { + "type": "ir.actions.client", + "tag": "reload", + } + + @api.model + def back_to_origin_login(self): + if request: + from_uid = request.session.impersonate_from_uid + if from_uid: + request.session.uid = from_uid + self.env["impersonate.log"].sudo().browse( + request.session.impersonate_log_id + ).write( + { + "date_end": fields.datetime.now(), + } + ) + request.env["res.users"].clear_caches() + request.session.impersonate_from_uid = False + request.session.impersonate_log_id = False + request.session.session_token = security.compute_session_token( + request.session, request.env + ) + logger.info( + f"IMPERSONATE: {self._get_partner_name(from_uid)} " + f"Logout as {self._get_partner_name(self._uid)}" + ) diff --git a/impersonate_login/readme/CONTRIBUTORS.rst b/impersonate_login/readme/CONTRIBUTORS.rst new file mode 100644 index 0000000000..dcae277c8c --- /dev/null +++ b/impersonate_login/readme/CONTRIBUTORS.rst @@ -0,0 +1 @@ +* Kévin Roche diff --git a/impersonate_login/readme/DESCRIPTION.rst b/impersonate_login/readme/DESCRIPTION.rst new file mode 100644 index 0000000000..7ffc13f484 --- /dev/null +++ b/impersonate_login/readme/DESCRIPTION.rst @@ -0,0 +1,7 @@ +This module allows to login as another user. +In the chatter, the user who is logged as another user is displayed. +The mails and messages are sent from the orignal user. +A table diplays the impersonated logins in technical. +The user can return to his own user by clicking on the button "Return to my user". +This module is very useful for the support team. +An alternative module will be auth_admin_passkey. diff --git a/impersonate_login/readme/USAGE.rst b/impersonate_login/readme/USAGE.rst new file mode 100644 index 0000000000..d0109247f9 --- /dev/null +++ b/impersonate_login/readme/USAGE.rst @@ -0,0 +1,2 @@ +1. On the top right corner, click my user and "switch login" +2. Same place to "return to my login" diff --git a/impersonate_login/security/group.xml b/impersonate_login/security/group.xml new file mode 100644 index 0000000000..e996175066 --- /dev/null +++ b/impersonate_login/security/group.xml @@ -0,0 +1,13 @@ + + + + + Impersonate Users + + + diff --git a/impersonate_login/security/ir.model.access.csv b/impersonate_login/security/ir.model.access.csv new file mode 100644 index 0000000000..3a5c10c53d --- /dev/null +++ b/impersonate_login/security/ir.model.access.csv @@ -0,0 +1,2 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_impersonate_log,impersonate logs,model_impersonate_log,base.group_user,1,1,0,0 diff --git a/impersonate_login/static/description/index.html b/impersonate_login/static/description/index.html new file mode 100644 index 0000000000..f56e86fcd8 --- /dev/null +++ b/impersonate_login/static/description/index.html @@ -0,0 +1,437 @@ + + + + + + +Impersonate Login + + + +
      +

      Impersonate Login

      + + +

      Beta License: AGPL-3 OCA/server-auth Translate me on Weblate Try me on Runboat

      +

      This module allows to login as another user. +In the chatter, the user who is logged as another user is displayed. +The mails and messages are sent from the orignal user. +A table diplays the impersonated logins in technical. +The user can return to his own user by clicking on the button “Return to my user”. +This module is very useful for the support team. +An alternative module will be auth_admin_passkey.

      +

      Table of contents

      + +
      +

      Usage

      +
        +
      1. On the top right corner, click my user and “switch login”
      2. +
      3. Same place to “return to my login”
      4. +
      +
      +
      +

      Bug Tracker

      +

      Bugs are tracked on GitHub 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.

      +

      Do not contact contributors directly about support or help with technical issues.

      +
      +
      +

      Credits

      +
      +

      Authors

      +
        +
      • Akretion
      • +
      +
      +
      +

      Contributors

      + +
      +
      +

      Maintainers

      +

      This module is maintained by the OCA.

      +Odoo Community Association +

      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.

      +

      Current maintainer:

      +

      Kev-Roche

      +

      This module is part of the OCA/server-auth project on GitHub.

      +

      You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

      +
      +
      +
      + + diff --git a/impersonate_login/static/src/css/navbar.scss b/impersonate_login/static/src/css/navbar.scss new file mode 100644 index 0000000000..556a38a5ee --- /dev/null +++ b/impersonate_login/static/src/css/navbar.scss @@ -0,0 +1,23 @@ +body.o_is_impersonated .o_menu_systray { + background: repeating-linear-gradient( + 135deg, + #32d804, + #32d804 10px, + #373435 10px, + #373435 20px + ); + border-bottom-left-radius: 20px; + + > li { + > a, + > label { + &:hover { + background-color: fade_out($o-navbar-inverse-link-hover-bg, 0.5); + } + } + } + + .show .dropdown-toggle { + background-color: fade_out($o-navbar-inverse-link-hover-bg, 0.5); + } +} diff --git a/impersonate_login/static/src/js/abstract_web_client.js b/impersonate_login/static/src/js/abstract_web_client.js new file mode 100644 index 0000000000..1c3ef6d444 --- /dev/null +++ b/impersonate_login/static/src/js/abstract_web_client.js @@ -0,0 +1,18 @@ +// Copyright 2024 Akretion (https://www.akretion.com). +// @author Kévin Roche +// License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +odoo.define("impersonate_login.AbstractWebClient", function (require) { + "use strict"; + + var AbstractWebClient = require("web.AbstractWebClient"); + var session = require("web.session"); + + AbstractWebClient.include({ + _onWebClientStarted: function () { + this._super.apply(this, arguments); + if (session.impersonate_from_uid) { + this.$el.addClass("o_is_impersonated"); + } + }, + }); +}); diff --git a/impersonate_login/static/src/js/user_menu.js b/impersonate_login/static/src/js/user_menu.js new file mode 100644 index 0000000000..ad3672ac1b --- /dev/null +++ b/impersonate_login/static/src/js/user_menu.js @@ -0,0 +1,66 @@ +// Copyright 2024 Akretion (https://www.akretion.com). +// @author Kévin Roche +// License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +odoo.define("impersonate_login.UserMenu", function (require) { + "use strict"; + + var UserMenu = require("web.UserMenu"); + var core = require("web.core"); + var session = require("web.session"); + var _t = core._t; + + UserMenu.include({ + start: function () { + this.toggleImpersonationLinks(); + return this._super.apply(this, arguments); + }, + + _onMenuImpersonate: function () { + var self = this; + this._rpc({ + model: "ir.model.data", + method: "xmlid_to_res_model_res_id", + args: ["impersonate_login.impersonate_res_users_tree"], + }).then(function (data) { + self.do_action({ + type: "ir.actions.act_window", + name: _t("Users"), + res_model: "res.users", + target: "new", + view_mode: "list", + views: [[data[1], "list"]], + domain: [["share", "=", false]], + }); + }); + }, + + _onMenuOrigin_login: function () { + var self = this; + return self + ._rpc({ + model: "res.users", + method: "back_to_origin_login", + args: [], + }) + .then(function () { + location.reload(true); + }); + }, + + toggleImpersonationLinks: function () { + var returnToLogin = this.$('[data-menu="origin_login"]'); + var impersonateLogin = this.$('[data-menu="impersonate"]'); + if (session.impersonate_from_uid) { + returnToLogin.removeClass("d-none"); + impersonateLogin.addClass("d-none"); + } else if (session.is_impersonate_user) { + returnToLogin.addClass("d-none"); + impersonateLogin.removeClass("d-none"); + } else { + returnToLogin.addClass("d-none"); + impersonateLogin.addClass("d-none"); + } + }, + }); +}); diff --git a/impersonate_login/static/src/xml/user_menu.xml b/impersonate_login/static/src/xml/user_menu.xml new file mode 100644 index 0000000000..bce12c050c --- /dev/null +++ b/impersonate_login/static/src/xml/user_menu.xml @@ -0,0 +1,22 @@ + + + + + + 🔙 To my Login + 🔄 Switch Login + + + diff --git a/impersonate_login/views/assets.xml b/impersonate_login/views/assets.xml new file mode 100644 index 0000000000..cf15b77905 --- /dev/null +++ b/impersonate_login/views/assets.xml @@ -0,0 +1,24 @@ + + +